<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://risencrypto.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://risencrypto.github.io/" rel="alternate" type="text/html" /><updated>2026-08-13T10:46:10+00:00</updated><id>https://risencrypto.github.io/feed.xml</id><title type="html">Risen Crypto</title><subtitle>Mathematical Cryptography, zkSNARKs</subtitle><author><name>RisenCrypto</name></author><entry><title type="html">Bulletproofs Inner Product Argument &amp;amp; Range Proofs in Monero using Bulletproofs</title><link href="https://risencrypto.github.io/Bulletproofs/" rel="alternate" type="text/html" title="Bulletproofs Inner Product Argument &amp;amp; Range Proofs in Monero using Bulletproofs" /><published>2025-02-04T00:00:00+00:00</published><updated>2025-02-04T00:00:00+00:00</updated><id>https://risencrypto.github.io/Bulletproofs</id><content type="html" xml:base="https://risencrypto.github.io/Bulletproofs/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<h5 id="notes">Notes</h5>
<p>$\mathbb F_p$ is a Finite Field. We use an Elliptic Curve $E(\mathbb F_p)$ over this field. The order of the curve is $q$ &amp; the discrete log problem is hard in the Group of the Curve. When we sample any random numbers in this post, please assume it’s sampled from $\mathbb F_q$.</p>

<p>The Prover is $\mathcal P$ &amp; the Verifier $\mathcal V$.</p>
<h3 id="prerequisites">Prerequisites</h3>

<h4 id="pedersen-commitments">Pedersen Commitments</h4>
<p>The basic Pedersen Commitment has been covered in the earlier Monero post - <a href="/Monero/#pedersen-commitments">Privacy and Anonymity in Monero
</a> .</p>

<h5 id="pedersen-vector-commitments">Pedersen Vector Commitments</h5>
<p>I use the following notations for vectors. The arrow on top denotes that it is a vector &amp; not just a single value</p>

<p>$\overrightarrow m = [m_0, m_1, m_2, m_3]$</p>

<p>For convenience, I represent vectors horizontally in this post except in case of vector polynomials where I represent the vector coefficients vertically.</p>

<p>I represent a vector of exponentiated scalars as</p>

<p>$\overrightarrow {a^n} = [a^0, a^1, a^2, …, a^n]$</p>

<p>Pedersen Commitments can be extended to commit a vector of elements.</p>

<p>The Pedersen Commitment for the vector  $\overrightarrow m$ is</p>

<p>$C_m = m_0 G_0 + m_1 G_1 + m_2 G_2+ m_3 G_3 + bB$</p>

<p>Here $b$ is the blinding factor &amp; $B, G_0, G_1, G_2, G_3$ are all generators &amp; the relation between the different Generators is not known.</p>

<p>The above commitment can also be written as</p>

<p>$C_m =  \overrightarrow m  \overrightarrow G + bB$</p>

<p>where $\overrightarrow G = [G_0, G_1, G_2, G_3]$ &amp; is called the “basis” committing $\overrightarrow m$</p>

<p>This can also be extended for committing multiple vectors in a single commitment</p>

<p>$C_{mn} = \overrightarrow m \overrightarrow H + \overrightarrow n \overrightarrow G + bB$</p>

<h5 id="pedersen-polynomial-commitments">Pedersen Polynomial Commitments</h5>
<p>Throughout this post, I present protocols &amp; proofs as interactive ones, but they would be used with the <a href="https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic">Fiat-Shamir heuristic</a> to make them non-interactive.</p>

<p>$p(x) = c_0 + c_1 x + c_2 x^2$</p>

<p>In order to commit to the polynomial, $\mathcal P$ makes a separate commitment to each of the coefficients &amp; sends them to $\mathcal V$.</p>

<p>$C_0 = c_0G + b_0 B$</p>

<p>$C_1 = c_1G + b_1 B$</p>

<p>$C_2 = c_2G + b_2 B$</p>

<p>where $b_0, b_1, b_2$ are randomly sampled blinding factors</p>

<p>$\mathcal P$ can do a zero knowledge opening of this polynomial commitment with the following Evaluation Proof</p>

<ul>
  <li>$\mathcal V$ randomly samples $u$ &amp; sends it to $\mathcal P$.</li>
  <li>
    <p>$\mathcal P$ evaluates $p(x)$ at $u$, $p_u = p(u) = p_0 + p_1u + p_2u^2$.</p>
  </li>
  <li>
    <p>$\mathcal P$ also computes $b =  b_0 +  b_1 u +  b_2 u^2$.</p>
  </li>
  <li>$\mathcal P$ sends $p_u$ &amp; $b$ to $\mathcal V$.</li>
  <li>$\mathcal V$ checks if $C_0 + C_1u + C_2u^2   \stackrel {?}{=} p_uG + bB$.</li>
</ul>

<p>If it is, then $\mathcal V$ accepts that the evaluation $p(u)$ is $p_u$ &amp; that $\mathcal P$ knows the polynomial $p(x)$ by the <a href="/Plonk/#the-schwartzzippel-lemma">Schwartz-Zippel Lemma</a>.</p>

<p>This works because</p>

<p>$p_uG + bB\space= (p_0 + p_1u + p_2u^2)G + (b_0 +  b_1 u +  b_2 u^2)B$</p>

<p>$\qquad\qquad =  p_0G + (p_1G + b_1B)u + (p_2G + b_2B )u^2 + b_0B)$</p>

<p>$\qquad\qquad =  C_0+ C_1u+C_2u^2$</p>

<h4 id="zero-knowledge-polynomial-product-proof">Zero Knowledge Polynomial Product Proof</h4>

<p>$l(x) = l_0 + l_1x$</p>

<p>$r(x) = r_0 + r_1x$</p>

<p>$t(x) = l(x) r(x) = (l_0 + l_1x)(r_0 + r_1x)$</p>

<p>$\qquad = l_0 r_0  + (l_0 r_1 + l_1 r_0)x + l_1 r_1 x^2$</p>

<p>Let $t_0  = l_0 r_0, t_1 = (l_0 r_1 + l_1 r_0), t_2 = l_1 r_1 $</p>

<p>$t(x) = t_0 + t_1x + t_2x^2$</p>

<p>$\mathcal P$ wants to prove that $t(x) = l(x)r(x)$</p>

<p>To prove this, she provides these proofs.</p>

<p>$1)$ Evaluation Proofs for $t(x), l(x)$ &amp; $r(x)$ separately using the method used in the previous section.</p>

<ul>
  <li>
    <p>$\mathcal P$ sends commitments to the coefficients of each of the 3 polynomials 
(total 7 commitments).</p>
  </li>
  <li>
    <p>$\mathcal V$ sends random $u$.</p>
  </li>
  <li>
    <p>$\mathcal P$ evaluates $l_u = l(u), r_u = r(u), t_u = t(u)$. $\mathcal P$ sends these values to $\mathcal V$.</p>
  </li>
  <li>
    <p>$\mathcal V$ checks the evaluation proof for each of the 3 polynomials using the method described in the earlier section &amp; rejects the proof it doesn’t verify.</p>
  </li>
</ul>

<p>$2)$ Proof that evaluation of $t$ at a random point is equal to the product of the evaluations of $l$ &amp; $r$ at the same point.</p>

<ul>
  <li>$\mathcal V$ checks if $t_u \stackrel {?}{=} l_u r_u$ and accepts the proof if it is.</li>
</ul>

<p>This involves $\mathcal P$ sending 7 commitments &amp; $\mathcal V$ checking 4 equalities. This can be optimized as below.</p>

<h5 id="optimized-proof">Optimized Proof</h5>

<p>In the earlier section, $\mathcal V$ verified $l(x)$ &amp; $r(x)$ separately, but this can be optimized by verifying both in a single step.</p>

<p>Commitment to $l(x)$ can be looked at as a commitment to the constant term (the term $x^0$ - i.e. the co-efficient with no $x$ terms) linearly combined with the linear term (term with $x^1$) combined in a <a href="/PLONKWHY/#linear-independence">linearly independent</a> way.</p>

<p>$C_{l(x)} = C_{l_0} + C_{l_1}x$</p>

<p>$C_{r(x)} = C_{r_0} + C_{r_1}x$</p>

<p>Both can be combined as</p>

<p>$S = C_{l(x=u)} + C_{r(x=u)} = C_{l_0} +C_{r_0} + C_{l_1}u + C_{r_1}u = C_0 + C_1u$</p>

<p>So instead of 4 commitments, $\mathcal P$ makes 2 commitments for $l$ &amp; $r$.</p>

<p>$C_0 = l_0 G + r_0 H + b_0 B$</p>

<p>$C_1 = l_1 G + r_1 H + b_1 B$</p>

<p>Commitments for $t(x)$ remain like before.</p>

<p>$C_{t_0} = l_0 r_0 G + b_{t_0}B$</p>

<p>$C_{t_1} = (l_0 r_1 + l_1 r_0) G + b_{t_1}B$</p>

<p>$C_{t_2} = l_1 r_1 G + b_{t_2}B$</p>

<p>$\mathcal P$ sends 5 commitments to $\mathcal V$.</p>

<p>$\mathcal V$s sends $u$ like before &amp; $\mathcal P$ evaluates $l, r, t$ at &amp; $u$ and sends the evaluations $l_u, r_u$ &amp; $t_u$ to $\mathcal V$. She also sends $b_t = b_{t_0} + b_{t_1}u + b_{t_2}u^2$ &amp; $b_{lr} = b_0 + u$.</p>

<p>$\mathcal V$ computes</p>

<p>$S = C_0 + C_1\space u$</p>

<p>$\mathcal V$ checks if $S \stackrel {?}{=} l_u G +r_eH + b_{lr}B$ - which is equivalent to checking both $l(x)$ &amp; $(x)$.</p>

<p>This works if $\mathcal P$ is honest because</p>

<p>$C_0 + C_1\space u = l_0G + r_0H + b_0B+ l_1uG + r_1uH + b_1uB$</p>

<p>$\qquad\qquad = (l_0 + l_1u)G + (r_0 + r_1u)H + (b_0 + b_1u)B$</p>

<p>$\qquad\qquad = l_u G +r_uH + b_{lr}B$</p>

<p>Other checks remain the same as before i.e. evaluation proof of $t(x)$ &amp; proof that $t_u = l_u r_u$.</p>

<h4 id="inner-product">Inner Product</h4>

<p>Two vectors,</p>

<p>$\overrightarrow m =[ m_0, m_1, m_2]$</p>

<p>$\overrightarrow n =[ n_0, n_1, n_2]$</p>

<p>The Inner Product of these 2 vectors is</p>

<p>$&lt;\overrightarrow m, \overrightarrow n&gt; = m_0 n_0 + m_1 n_1 + m_2 n_2  $</p>

<p>i.e. the corresponding elements of the 2 vectors are multiplied with each other &amp; then added up. Note that the output of an inner product is a scalar/single value &amp; not a vector. An inner product is also called a dot product in some contexts.</p>

<p>A Vector Commitment can also be represented as an Inner Product.</p>

<p>$C_m = bB +  m_0\space G_0 + m_1\space G_1 + m_2\space G_2+ m_3\space G_3$</p>

<p>The above can be written as an inner product.</p>

<p>$C_m= bB + &lt;\overrightarrow m, \overrightarrow G&gt;$</p>

<p>A Polynomial $p(x) = p_0 + p_1x + p_2x^2 + … + p_nx^n$</p>

<p>can be written as $p(x) = &lt;\overrightarrow p, \overrightarrow {x^n}&gt;$ where $\overrightarrow p$ is the vector of coefficients $[p_0, p_1, p_2, …, p_n]$.</p>

<p>The evaluation of $p$ at $u$ would be $&lt;\overrightarrow p, \overrightarrow{u^n}&gt;$.</p>

<h4 id="hadamard-product">Hadamard Product</h4>
<p>A Hadamard product of 2 vectors is represented as</p>

<p>$\overrightarrow m \circ \overrightarrow n = [m_0  n_0, \space\space  m_1  n_1, \space\space m_2  n_2]$</p>

<p>Note that unlike the inner product, the output of the Hadamard product is a vector. When the elements of the Hadamard product output are added together, you get the Inner Product.</p>

<p>Since the output a Hadamard Product is a vector, a Hadamard product can be an input to an inner product, i.e.</p>

<p>$&lt; \overrightarrow m \circ  \overrightarrow n, \space \space \overrightarrow a&gt;$</p>

<p>If the hadamard product of $ \overrightarrow m$ &amp; $\overrightarrow n$ gives us the vector $\overrightarrow p = [m_0  n_0, \space\space m_1  n_1, \space\space m_2  n_2 ]$, then the Inner Product $&lt;\overrightarrow  m \circ \overrightarrow n , a&gt;$ would be the same as $&lt;\overrightarrow p, \overrightarrow a&gt;$.</p>

<h4 id="product-algebra">Product Algebra</h4>

<p>Some rearranging of Inner Products &amp; Hadamard Products which we will be using later.</p>

<ul>
  <li>$\quad &lt;\overrightarrow m,\space\space \overrightarrow p+\overrightarrow q&gt; =  m_0 (p_0+q_0) + m_1 (p_1+q_1) + m_2 (p_2+q_2) $</li>
</ul>

<p>$\qquad = m_0 p_0+m_0 q_0 + m_1 p_1+m_1 q_1 + m_2 p_2+m_2 q_2 $</p>

<p>$\qquad = (m_0 p_0 + m_1 p_1 + m_2 p_2 ) + (m_0 q_0 + m_1 q_1 + +m_2 q_2)$</p>

<p>$\qquad = &lt;\overrightarrow m, \overrightarrow p&gt; + &lt;\overrightarrow m, \overrightarrow q&gt;$</p>

<ul>
  <li>The above also means</li>
</ul>

<p>$\quad &lt;\overrightarrow m+\overrightarrow n, \overrightarrow p + \overrightarrow q&gt; = &lt;\overrightarrow m+\overrightarrow n,\overrightarrow p&gt; + &lt;\overrightarrow m+\overrightarrow n,\overrightarrow q&gt;
= &lt;\overrightarrow m, \overrightarrow p&gt; + &lt;\overrightarrow n,\overrightarrow p&gt; + &lt;\overrightarrow m, \overrightarrow q&gt; + &lt;\overrightarrow n,\overrightarrow q&gt;$</p>

<ul>
  <li>We can also rearrange an Inner product as an Inner Product containing a Hadamard Product.</li>
</ul>

<p>$\quad &lt;\overrightarrow m,\overrightarrow n&gt; = m_0 n_0 + m_1 n_1 + m_2 n_2$</p>

<p>$\qquad = 1^0 ( m_0 n_0) + 1^1 ( m_1 n_1) + 1^2 ( m_2 n_2) $</p>

<p>$\qquad = &lt;\overrightarrow {1^n}, \overrightarrow m\circ \overrightarrow n&gt;$</p>

<ul>
  <li>Consider a scalar $s$,</li>
</ul>

<p>$\qquad s &lt;\overrightarrow m, \overrightarrow n&gt; = s  (m_0 n_0 + m_1 n_1 + m_2 n_2 )$</p>

<p>$\qquad = (s m_0)n_0 + (s m_1) n_1 + (s m_2) n_2$</p>

<p>$\qquad = &lt;s\overrightarrow m, \overrightarrow n&gt; = &lt;\overrightarrow  m, s\overrightarrow n&gt;$</p>

<ul>
  <li>$\overrightarrow m = [m_0, m_1, m_2, m_3] = [m_0.1^0, m_1.1^1, m_2.1^2, m_3.1^3] = \overrightarrow m \circ \overrightarrow 1^4$</li>
</ul>

<p>$\qquad$ So, $\overrightarrow m=\overrightarrow m \circ \overrightarrow 1^4$</p>

<ul>
  <li>
    <p>$\overrightarrow m \circ s1^4 = s\overrightarrow m\circ 1^4 = s\overrightarrow m$</p>
  </li>
  <li>
    <p>Consider $\overrightarrow m$ is made of two halves $\overrightarrow m_L$ &amp; $\overrightarrow m_R$</p>
  </li>
</ul>

<p>$\qquad$ i.e. $\overrightarrow m = [m_0,m_1, m_2, m_3]$</p>

<p>$\qquad \overrightarrow m_L = [m_0, m_1]$ &amp; $\overrightarrow m_R = [m_2, m_3]$</p>

<p>$\qquad$ and likewise $n_L$ &amp; $n_R$ are the two halves of $n$,</p>

<p>$\qquad$ If concatenation is represented by $\oplus$, then (Note that $\oplus$ is different than $+$)</p>

<p>$\qquad \overrightarrow m = \overrightarrow m_L \oplus \overrightarrow m_R$ &amp; $\overrightarrow n = \overrightarrow n_L \oplus \overrightarrow n_R$</p>

<p>then 
$&lt;\overrightarrow m, \overrightarrow n&gt; = m_0 n_0 + m_1 n_1 + m_2 n_2 + m_3 n_3  = &lt;\overrightarrow m_L, \overrightarrow n_L&gt; + &lt;\overrightarrow m_R, \overrightarrow n_R&gt;$</p>

<h4 id="vector-polynomial-commitments">Vector Polynomial Commitments</h4>

<p>A vector polynomial is a polynomial each of whose coefficients is a vector.</p>

<p>$\overrightarrow p(x) = \begin{bmatrix} 2 \cr 3 \cr 4 \end{bmatrix} + \begin{bmatrix} 4 \cr 5 \cr 6 \end{bmatrix} x + \begin{bmatrix} 6 \cr 7 \cr 8 \end{bmatrix} x^2$</p>

<p>Let us evaluate $\overrightarrow p(x)$ at a point $x=11$.</p>

<p>$\overrightarrow p(11) = \begin{bmatrix} 2 \cr 3 \cr 4 \end{bmatrix} + \begin{bmatrix} 4 \cr 5 \cr 6 \end{bmatrix} 11 + \begin{bmatrix} 6 \cr 7 \cr 8 \end{bmatrix} 11^2$</p>

<p>$\qquad\qquad = \begin{bmatrix} 2 \cr 3 \cr 4 \end{bmatrix} + \begin{bmatrix} 411 \cr 511 \cr 611 \end{bmatrix}  + \begin{bmatrix} 6 11^2 \cr 711^2 \cr 811^2 \end{bmatrix} $</p>

<p>$\qquad\qquad = \begin{bmatrix} 139 \cr 61 \cr 194 \end{bmatrix} $</p>

<div class="boxed">

The evaluation of a vector polynomial is a vector.

</div>

<hr style="clear:both;" />

<p>$\overrightarrow l(x) = \overrightarrow l_0  + \overrightarrow l_1x$</p>

<p>$\overrightarrow r(x) = \overrightarrow r_0+ \overrightarrow r_1x$</p>

<p>$t(x) = &lt;\overrightarrow l(x), \overrightarrow r(x)&gt;$</p>

<p>$\qquad = &lt;\overrightarrow l_1, \overrightarrow r_1&gt; + &lt;\overrightarrow l_0, \overrightarrow r_1&gt;x + &lt;\overrightarrow l_1, \overrightarrow r_0&gt;x + &lt;\overrightarrow l_0, \overrightarrow r_0&gt;x^2$</p>

<p>Since the inner product of vectors is a scalar, each of the co-efficients of $t(x)$ would also be a scalar &amp; hence $t(x)$ is a regular polynomial &amp; not a vector polynomial.</p>

<p>$\overrightarrow l(x) = \begin{bmatrix}3 \cr 5\end{bmatrix} + \begin{bmatrix}2\cr 4\end{bmatrix}x $</p>

<p>$\overrightarrow r(x) = \begin{bmatrix} 2\cr 7\end{bmatrix} + \begin{bmatrix} 1 \cr 3\end{bmatrix} x$</p>

<p>$t(x) = &lt;\overrightarrow l(x), \overrightarrow r(x)&gt; = &lt;\begin{bmatrix}3\cr 5\end{bmatrix},\begin{bmatrix} 2\cr 7\end{bmatrix}&gt; + (&lt;\begin{bmatrix}2\cr 4\end{bmatrix}, \begin{bmatrix} 2\cr 7\end{bmatrix}&gt; + &lt;\begin{bmatrix}3\cr 5\end{bmatrix},\begin{bmatrix} 1\cr 3\end{bmatrix}&gt;)x + &lt;\begin{bmatrix}2\cr 4\end{bmatrix},\begin{bmatrix}1\cr 3\end{bmatrix}&gt;x^2$</p>

<p>$t(x) = 41  + 50x + 14 x^2$</p>

<p>Since each of the co-efficients of a Vector Polynomial is a vector, a $\mathcal P$ can make a Pedersen Vector Commitment to each of the Vector Co-efficients of the Polynomial and use same method we used for  proving a Vector Polynomial Product.</p>

<h3 id="bulletproofs">Bulletproofs</h3>

<p>Bulletproofs are a short proof without a trusted setup to prove the Inner Product Argument (IPA).</p>

<p>Bulletproofs lets $\mathcal P$ convince $\mathcal V$ that she knows 2 vectors  $\overrightarrow m, \overrightarrow n $,  each of length $N$ such that their commitment is</p>

<p>$S = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H$</p>

<p>and</p>

<p>$c = &lt;\overrightarrow m, \overrightarrow n&gt;$</p>

<p>$\overrightarrow G$ &amp; $\overrightarrow H$ are the bases for $\overrightarrow m$ &amp; $\overrightarrow n$ respectively</p>

<p><strong>Note:</strong> The commitment $S$ is a binding commitment but not a hiding commitment because there is no blinding factor.</p>

<p>Instead of proving these 2 statements separately, $\mathcal P$ wants to combine them into one statement &amp; prove it such that proving the one statement will prove both of the above. Since $S$ is an Elliptic Curve point, we will convert $c$ also to a point before combining them.</p>

<p>Let $V$ be another unrelated Generator. We both sides of the 2nd statement by $V$.</p>

<p>$cV = &lt;\overrightarrow m, \overrightarrow n&gt;V$</p>

<p>$\mathcal P$ has to prove 2 statements</p>

<ul>
  <li>
    <p>$S = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H$</p>
  </li>
  <li>
    <p>$cV = &lt;\overrightarrow m, \overrightarrow n&gt;V$</p>
  </li>
</ul>

<p>$\mathcal P$ sends $S$ &amp; $c$ to $\mathcal V$. $\mathcal V$ samples a random value $r$ &amp; sends it to $\mathcal V$.</p>

<p>The 2 statements can be combined in a <a href="/PLONKWHY/#linear-independence">linearly independent way</a> using the randomness ($r$).</p>

<p>$S + crV = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H + &lt;\overrightarrow m, \overrightarrow n&gt;rV$</p>

<p>Because the 2 terms are linearly independent, if $\mathcal P$ proves that the Left Hand Side is equal to the Right Hand Side, then it would prove that with a very high probability that $S = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H$ and $c = &lt;\overrightarrow m, \overrightarrow n&gt;$.</p>

<p>Let $U = rV$ ($U$ is now a new generator which is unrelated to the 2 sets of generators denoted by $\overrightarrow H$ &amp; $\overrightarrow G$) &amp; let $P = S + cU$.</p>

<p>Since $\mathcal V$ knows $S$ &amp; $c$, he can compute $P$.</p>

<p>So $\mathcal P$ now has to prove that</p>

<p>$P = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H + &lt;\overrightarrow m, \overrightarrow n&gt;U$</p>

<p>Let us say we didn’t include the random $r$ sent by $\mathcal V$ while combining the 2, then the proof wouldn’t be sound. $\mathcal P$ could prove that $c_{fake} = &lt;\overrightarrow m, \overrightarrow n&gt;$ even though the actual value is c. Let’s see how.</p>

<p>Instead of sending the real commitment $S$, $\mathcal P$ could construct a value</p>

<p>$S_{fake} = S + cV - c_{fake}V$</p>

<p>&amp; send $S_{fake}$ to $\mathcal V$ along with $c_{fake}$</p>

<p>Now when $\mathcal V$ constructs $P$, it would be constructed thus</p>

<p>$P = S_{fake} + c_{fake}V$</p>

<p>which would become</p>

<p>$P = S + cV - c_{fake}V + c_{fake}V$</p>

<p>i.e.</p>

<p>$P = S + cV$ which can be proven true even though $c_{fake} \ne &lt;\overrightarrow m, \overrightarrow n&gt;$. Hence after $\mathcal P$ sends $S$ &amp; $c$ to $\mathcal V$, $\mathcal V$ sends him random $r$ which is used to combine the 2 parts in a linearly independent way.</p>

<h4 id="the-protocol">The Protocol</h4>

<p>$\mathcal P$ has to prove</p>

<p>$P = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H + &lt;\overrightarrow m, \overrightarrow n&gt;U$</p>

<p>where the length of each of the vectors is $N$.</p>

<p>$\mathcal P$ can send $\overrightarrow m$ &amp; $\overrightarrow n$ to $\mathcal V$ &amp; $\mathcal V$ can compute the Inner Product &amp; verify that it’s equal to $v$. However, she would to have send $2N$ elements. The algorithm aims to reduce the number of elements sent for the proof.</p>

<p>$\mathcal P$ splits the 2 vectors into half, 
$\overrightarrow m_L$ is the left half of $\overrightarrow m$ &amp; $\overrightarrow m_R$ is the right half. Each of these 2 vectors is of size $N_1 = \frac {N}{2}$. Likewise, $\overrightarrow n_L$ &amp; $\overrightarrow n_R$.</p>

<p>Similarly, each of the Generator vectors is  split into $2$ i.e.  $\overrightarrow G_L \text{ and }\overrightarrow G_R, \overrightarrow H_L \text{ and } \overrightarrow H_R$.</p>

<p>$P = \overrightarrow m_L \overrightarrow G_L + \overrightarrow m_R  \overrightarrow G_R + \overrightarrow n_L \overrightarrow H_L + \overrightarrow n_R \overrightarrow H_R+ &lt;\overrightarrow m, \overrightarrow n&gt;U$</p>

<p>$&lt;\overrightarrow m,\overrightarrow n&gt; = &lt;m_L, n_L&gt; + &lt;m_R, n_R&gt;$</p>

<div class="boxed">

$Note: \overrightarrow m = \overrightarrow m_L \oplus \overrightarrow m_R$ and  $\overrightarrow m \ne \overrightarrow m_L + \overrightarrow m_R$

$\oplus$ &amp; $+$ are different.

</div>

<hr style="clear:both;" />

<p>So,
$P = \overrightarrow m_L \overrightarrow G_L + \overrightarrow m_R  \overrightarrow G_R + \overrightarrow n_L \overrightarrow H_L + \overrightarrow n_R \overrightarrow H_R+ (&lt;m_L, n_L&gt; + &lt;m_R, n_R&gt;)U$</p>

<p>$\mathcal P$ computes $L_1$ &amp; $R_1$ &amp; sends them to $\mathcal V$.</p>

<p>$L_1 = \overrightarrow m_L \overrightarrow G_R + \overrightarrow n_R \overrightarrow H_L + &lt;\overrightarrow m_L, \overrightarrow n_R&gt;U$</p>

<p>$R_1 = \overrightarrow m_R \overrightarrow G_L + \overrightarrow n_L \overrightarrow H_R + &lt;\overrightarrow m_R, \overrightarrow n_L&gt;U$</p>

<p>$\mathcal V$ samples a random $x_1$ &amp; sends it to $\mathcal P$.</p>

<p>Let $P_1 = x_1^2 L_1 + P + x_1^{-2} R_1$</p>

<p>We will now substitute the values of $L_1, R_1$ and $P$ into $P_1$</p>

<p>$P_1 = x_1^2 (\overrightarrow m_L \overrightarrow G_R + \overrightarrow n_R \overrightarrow H_L + &lt;\overrightarrow m_L, \overrightarrow n_R&gt;U) $</p>

<p>$\qquad + \overrightarrow m_L \overrightarrow G_L + \overrightarrow m_R  \overrightarrow G_R + \overrightarrow n_L \overrightarrow H_L + \overrightarrow n_R \overrightarrow H_R+ (&lt;\overrightarrow m_L, \overrightarrow n_L&gt; + &lt;\overrightarrow m_R, \overrightarrow n_R&gt;)U $</p>

<p>$\qquad +  x_1^{-2} 
(\overrightarrow m_R \overrightarrow G_L + \overrightarrow n_L \overrightarrow H_R + &lt;\overrightarrow m_R, \overrightarrow n_L&gt;U)$</p>

<p><br /></p>

<p>$\qquad =(\overrightarrow m_L + x_1^{-2} \overrightarrow m_R) \overrightarrow G_L +  (x_1^2 \overrightarrow m_L  + \overrightarrow m_R ) \overrightarrow G_R + (x_1^2  \overrightarrow n_R  + \overrightarrow n_L) \overrightarrow H_L+ (x_1^{-2} \overrightarrow n_L + \overrightarrow n_R) \overrightarrow H_R$</p>

<p>$\qquad +(x_1^2 &lt;\overrightarrow m_L, \overrightarrow n_R&gt; + &lt;\overrightarrow m_L, \overrightarrow n_L&gt; + &lt;\overrightarrow m_R, \overrightarrow n_R&gt; + x_1^{-2}  &lt;\overrightarrow m_R, \overrightarrow n_L&gt;)U$</p>

<p><br /></p>

<p>$\qquad = (x_1 \overrightarrow m_L + x_1^{-1} \overrightarrow m_R) x_1^{-1} \overrightarrow G_L+ (x_1 \overrightarrow m_L + x_1^{-1}\overrightarrow m_R)x_1 \overrightarrow G_R+ ( x_1 \overrightarrow n_R  + x_1^{-1}\overrightarrow n_L) x_1 \overrightarrow H_L+ (x_1^{-1} \overrightarrow n_L + x_1\overrightarrow n_R) x_1^{-1} \overrightarrow H_R$</p>

<p>$\qquad +(x_1^2 &lt;\overrightarrow m_L, \overrightarrow n_R&gt; + &lt;\overrightarrow m_L, \overrightarrow n_L&gt; + &lt;\overrightarrow m_R, \overrightarrow n_R&gt; + x_1^{-2}  &lt;\overrightarrow m_R, \overrightarrow n_L&gt;)U$</p>

<p><br /></p>

<p>$\qquad = (x_1 \overrightarrow m_L + x_1^{-1} \overrightarrow m_R) (x_1^{-1} \overrightarrow G_L + x_1 \overrightarrow G_R) + ( x_1 \overrightarrow n_R  + x_1^{-1}\overrightarrow n_L)(x_1 \overrightarrow H_L + x_1^{-1} \overrightarrow H_R) $</p>

<p>$\qquad +( &lt;x_1 \overrightarrow m_L, x_1 \overrightarrow n_R&gt; + &lt;x_1 \overrightarrow m_L, x_1^{-1}\overrightarrow n_L&gt; + &lt;x_1^{-1}\overrightarrow m_R, x_1 \overrightarrow n_R&gt; +   &lt;x_1^{-1}\overrightarrow m_R, x_1^{-1}\overrightarrow n_L&gt;)U$</p>

<p><br /></p>

<p>$ P_1 = (x_1 \overrightarrow m_L + x_1^{-1} \overrightarrow m_R) (x_1^{-1} \overrightarrow G_L + x_1 \overrightarrow G_R) + ( x_1 \overrightarrow n_R  + x_1^{-1}\overrightarrow n_L)(x_1 \overrightarrow H_L + x_1^{-1} \overrightarrow H_R)  +( &lt;x_1 \overrightarrow m_L  + x_1^{-1} \overrightarrow m_R&gt;, &lt;x_1^{-1} \overrightarrow n_L + x_1 \overrightarrow n_R&gt;)U$</p>

<p>Let</p>

<p>$\overrightarrow m_1 = x_1 \overrightarrow m_L + x_1^{-1} \overrightarrow m_R$</p>

<p>$\overrightarrow n_1 = x_1 \overrightarrow n_R  + x_1^{-1}\overrightarrow n_L$</p>

<p>Both $\mathcal P$ &amp; $\mathcal V$ also compute new bases</p>

<p>$\overrightarrow G_1 = x_1^{-1} \overrightarrow G_L + x_1 \overrightarrow G_R$</p>

<p>$\overrightarrow H_1 = x_1 \overrightarrow H_L + x_1^{-1} \overrightarrow H_R$</p>

<p>So, proving $P = \overrightarrow m \overrightarrow G + \overrightarrow n \overrightarrow H + &lt;\overrightarrow m, \overrightarrow n&gt;U$ has reduced to proving</p>

<p>$P_1 = \overrightarrow m_1 \overrightarrow G_1 + \overrightarrow n_1 \overrightarrow H_1 + &lt;\overrightarrow m_1, \overrightarrow n_1&gt;U$</p>

<p>$\mathcal P$ can prove the proof for $P_1$ by sending $\overrightarrow m_1$ &amp; $\overrightarrow n_1$ &amp; $\mathcal V$ can check the inner product. The number of elements to be sent has reduced to $2N_1 = N$ (i.e. $N_1$ elements in each vector) which is half of what she would have to send for proving the proof with $P$.</p>

<p>Instead, she can repeat the steps after dividing $\overrightarrow m_1$ &amp; $\overrightarrow n_1$ again into left &amp; right vectors each &amp; $\mathcal V$ sending a new $x_1$. She keeps repeating these steps till in the final round (i.e. round $f = log (N)$), she has to prove</p>

<p>$P_{f} = m_f G_f +  n_f  H_f + m_f  n_fU$</p>

<p>Here, each of $m_f$ &amp; $n_f$ are single elements &amp; not vectors &amp; hence she has to send only 2 elements to $\mathcal V$. $\mathcal V$ can compute the inner product &amp; verify if $P_f$ is as claimed. If it is, that would mean $P_{f-1}$ is as claimed by $\mathcal P$ in the previous round. As we continue unrolling to the beginning, it would prove that $P$ is as claimed by $\mathcal P$, thus ending the proof.</p>

<p>So, the instead of sending 2 vectors $\overrightarrow m$ &amp; $\overrightarrow n$ each of size $s$, $\mathcal P$ only sends 
$L_1, R_1, L_2, R_2, …, m_f, n_f$ &amp; the final product $c_f = m_f n_f$.</p>

<p>So, Bulletproofs has reduced the number of elements $\mathcal P$ needs to send to $\mathcal V$ from $2N$ to $2log(N)$.</p>

<h4 id="optimization">Optimization</h4>

<p>In the protocol, we said that $\mathcal V$ computes new bases in each round. For e.g. in round 1</p>

<p>$\overrightarrow G_1 = x_1^{-1} \overrightarrow G_L + x_1 \overrightarrow G_R$</p>

<p>&amp; similarly for computing $\overrightarrow H_1$ from $\overrightarrow H_L$ &amp; $\overrightarrow H_R$.</p>

<p>Similarly in round 2, $\overrightarrow G_2$ would be computed from $\overrightarrow G_{1L}$ &amp; $\overrightarrow G_{1R}$. And $\overrightarrow H_2$ also similarly.</p>

<p>However, $\mathcal V$ doesn’t really do anything with these updated bases in each round because he doesn’t do any checks till the final round. He needs the final updated bases only in the final round. So, he saves his $x_i$s from each round &amp; finally computes the final $G_l$ &amp; $H_l$ which will be a function of our starting $\overrightarrow G$ &amp; $\overrightarrow H$ &amp; all the $x_i$s.</p>

<h5 id="soundness">Soundness</h5>

<p>In each round, we used a random $x_i$ &amp; scaled up the left halves by $x_i$ &amp; we scaled down the right half by $x_i^{-1}$. This is done so that $\mathcal P$ cannot fake a proof. We saw earlier how without using a random $r$ to create $U = rV$, $\mathcal P$ could prove $c_{fake} = &lt;\overrightarrow m, \overrightarrow n&gt;$ by crafting a $S_{fake}$. Similarly in each round, $\mathcal P$ instead of sending the correctly computed $L$ &amp; $R$ could craft $L_{fake}$ &amp; $R_{fake}$ such that everything matches &amp; if he does this in each round, the final $&lt;m_l, n_l&gt;$ can be made to equal $c_{fake}$. To prevent this, in each round, after $\mathcal P$ sends $L_i$ &amp; $R_i$, $\mathcal V$ samples a random $x_i$ sends it to $\mathcal P$. And then $\mathcal P$ scales the left &amp; right halves of that round by $x_i$ &amp; $x_i^{-1}$ respectively.</p>

<h3 id="range-proofs-in-monero">Range Proofs in Monero</h3>

<p>In the <a href="/Monero/#ringct">Monero Post</a>, we saw how validators can verify that the sum of the inputs of a transaction is greater than the sum of the outputs even though the amounts of the values are hidden using Pedersen Commitments. This check by itself is not enough because of wraparound which happens in Finite Fields. Consider a transaction with 2 inputs &amp; 2 outputs. Alice uses 2 UTXOs of value $10$ &amp; $15$ to send Bob $17$ moneros &amp; sends back change of $7$ to herself.</p>

<p>$in_1 = 10, in_2 = 15, out_1 = 17, out_2 = 7$</p>

<p>Because Pedersen Commitments are homomorphic, we can check if $C_{in_1} + C_{in_2} \ge C_{out_1} + C_{out_2}$ &amp; the above transaction would verify.</p>

<p>However, the scalars in Monero &amp; other blockchains operate in a finite field &amp; not in the field of reals or integers. The actual field is a very large field but for ease of understanding, let’s assume they operate in the field $\mathbb F_{7841}$</p>

<p>Now, if Alice sets $out_1 = 30$ &amp; $out_2 = 7835$. In the field $\mathbb F_{7841}$, $30 + 7835 = 24$, so the validation would work! So, Alice spent 2 UTXOs of value $10$ &amp; $15$ &amp; sent Bob $17$ &amp; also managed to get back $7835$ Moneros as change - i.e. she now possesses a UTXO worth $7835$ - she has created Moneros out of thin air.</p>

<p>So, we need to verify if each amount hidden by a commitment is in a particular range of values or not. On the blockchain, each amount needs to be between $0$ and $2^{64} - 1$.</p>

<h4 id="constructing-the-inner-product">Constructing the Inner Product</h4>

<p>$\mathcal P$ has provided a Pedersen commitment to an output value $v$. She also has to prove that $v \in \lbrace 0, 1, …, 2^{64} -1 \rbrace$.</p>

<p>To prove this, she first represents $v$ as a binary vector. Let’s take an example of $v = 101$ (in decimal).</p>

<p>This can be represented as a vector of bits</p>

<p>$12^0 + 0 2^1 + 12^2 + 0 2^3 + 0 2^4 + 1 2^5 + 1 2^6 = 101$</p>

<p>$\overrightarrow a_L = [1,0,1,0,0,1,1]$</p>

<p>Let’s create another vector $\overrightarrow a_R$ which is the complement of $\overrightarrow a_L$ - i.e. we create $\overrightarrow a_R$ by subtracting 1 from each element of $ \overrightarrow a_L$ - i.e. by subtracting  a bit vector of all $1$s (denoted as $\overrightarrow{1^n}$) from  $ \overrightarrow a_L$.</p>

<p>$\overrightarrow a_R = \overrightarrow a_L - \overrightarrow{1^n} $</p>

<p>$\overrightarrow a_R = [0, 1, 0,1,1,0,1,1]$</p>

<p>To prove $v \in \lbrace 0, 1, …, 2^{64} -1 \rbrace$, we have to prove 3 things.</p>

<p>$1)$ Prove $\overrightarrow a_L$ is a vector representing the decomposition of $v$.</p>

<p>i.e. $v = \overrightarrow a_L[0]2^0 + \overrightarrow a_L[1] 2^1 + …$</p>

<p>This can be represented as an inner product of 2 vectors. So, we have to prove this inner product</p>

<p>$&lt;\overrightarrow a_L, \overrightarrow {2^n}&gt; = v$</p>

<p>$2)$ Prove each element of $\overrightarrow a_L$ is a $0$ or a $1$ - i.e. the decomposition was a bitwise decomposition.</p>

<p>If you compare the vectors $\overrightarrow a_L$ &amp; $\overrightarrow a_R$, you will see that if you multiply each element of $\overrightarrow a_L$ with the corresponding element of $\overrightarrow a_R$, then the product will be $0$ only if the element of $\overrightarrow a_L$ was either a $0$ or a $1$.</p>

<p>Let’s say one of the elements of $\overrightarrow a_L$ was 5, then the corresponding element of $\overrightarrow a_R$ would be $-4$ &amp; hence the multiplication of the two would not be $0$.</p>

<p>So, proving that each such product is $0$ will  prove that $\overrightarrow a_L$ is a bit vector.</p>

<p>Is it enough to check if $&lt;\overrightarrow a_L, \overrightarrow a_R&gt; = 0$?</p>

<p>No, because if one of the element-wise product is say $4$ &amp; a different element wise product is $-4$, then they would cancel each other out &amp; the inner product could end up as $0$ even if each individual product was not $0$.</p>

<p>Let’s say each vector is of size $4$, i.e.</p>

<p>$\overrightarrow a_L = [l_0, l_1, l_2, l_3]$</p>

<p>$\overrightarrow a_R = [r_0,r_1, r_2, r_3]$</p>

<p>We have already determined that it would not be enough to check if $l_0 r_0 + l_1 r_1 + l_2 r_2 + l_3 r_3  \stackrel {?}{=} 0$.</p>

<p>We have to first combine all individual product terms in a linearly independent way. After $\mathcal P$ commits to the vector, $\mathcal V$ samples a random variable $y$ &amp; sends it to $\mathcal V$. The vector $\overrightarrow {y^4} = [y^0, y^1, y^2, y^3]$ is a linearly independent set.</p>

<p>This makes the individual terms of $l_0 r_0 y^0,\space \space l_1 r_1 y^1,\space \space   l_2 r_2  y^2,\space \space  l_3 r_3 y^3$ also linearly independent, so if their sum is $0$, then it means each of the $l_i r_i$ is $0$.</p>

<p>The Hadamard Product $\overrightarrow a_R \circ \overrightarrow{y^n} = [r_0 y^0 \space\space, r_1  y^1\space\space, r_2  y^2\space\space, r_3  y^3]$.</p>

<p>So, the inner product</p>

<p>$&lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt; = l_0r_0 y^0 + l_1r_1 y^1 + l_2r_2 y^2 + l_3r_3y^3$</p>

<p>So, it’s sufficient to check if $&lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt; \stackrel {?}{=} 0$. If it is, then it means that $v$’s decomposition into $\overrightarrow  a_L$ is indeed a bitwise decomposition.</p>

<p>$3)$ Prove $\overrightarrow a_R = \overrightarrow a_L - \overrightarrow{1^n}$
i.e. each element of $\overrightarrow a_R$ is a bitwise complement of the corresponding element of $\overrightarrow a_L$.</p>

<p>If each element of the vector $\overrightarrow a_L - \overrightarrow {1^n} - \overrightarrow a_R$ is $0$, then it means that $\overrightarrow a_R$ is the bitwise complement of $\overrightarrow a_L$. Again, we combine each element of this vector using the linearly independent set of $\overrightarrow {y^n}$ to create an inner product.</p>

<p>So, we have to prove that $&lt;\overrightarrow a_L - \overrightarrow {1^n} - \overrightarrow a_R, \space\space \overrightarrow {y^n}&gt; = 0$.</p>

<p>So, we have 3 things to prove</p>

<ul>
  <li>
    <p>$&lt;\overrightarrow a_L, \overrightarrow {2^n}&gt;  = v$</p>
  </li>
  <li>
    <p>$&lt;\overrightarrow a_L - \overrightarrow {1^n} - \overrightarrow a_R, \space\space \overrightarrow {y^n}&gt; = 0$</p>
  </li>
  <li>
    <p>$&lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt;= 0$</p>
  </li>
</ul>

<p>To transform 3 checks into one, we can again combine it in a linearly independent way.</p>

<p>$\mathcal V$ samples a random $z$ &amp; sends it to $\mathcal P$. $\mathcal P$ makes the 3 equations linearly independent by multiplying with the set $[z^0, z^1, z^2]$ and combines them</p>

<ul>
  <li>
    <p>$z^2 &lt;\overrightarrow a_L, \overrightarrow {2^n}&gt;  = z^2  v$</p>
  </li>
  <li>
    <p>$z^1  &lt;\overrightarrow a_L - \overrightarrow{1^n} - \overrightarrow a_R, \space\space \overrightarrow{y^n}&gt; = 0$</p>
  </li>
  <li>
    <p>$z^0  &lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt;= 0$</p>
  </li>
</ul>

\[z^2 &lt;\overrightarrow a_L, \overrightarrow {2^n}&gt;  + z  &lt;\overrightarrow a_L - \overrightarrow{1^n} - \overrightarrow a_R, \space\space \overrightarrow{y^n}&gt; + &lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt; = z^2  v\]

<p>Simplifying, we get</p>

\[z^2  v = z^2 &lt;\overrightarrow a_L, \overrightarrow{2^n}&gt;  + z  &lt;\overrightarrow a_L, \overrightarrow{y^n}&gt; -  z  &lt;\overrightarrow {1^n}, \overrightarrow{y^n}&gt; - z  &lt;\overrightarrow a_R, \overrightarrow{y^n}&gt; +  &lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt;\]

\[z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt;= z^2 &lt;\overrightarrow a_L, \overrightarrow {2^n}&gt;  + z  &lt;\overrightarrow a_L, \overrightarrow {y^n}&gt; - z  &lt;\overrightarrow {1^n}, \overrightarrow a_R \circ \overrightarrow {y^n}&gt; +  &lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt;\]

\[z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt;=  &lt;\overrightarrow a_L, z^2 \space \overrightarrow {2^n}&gt;  +  &lt;\overrightarrow  a_L, z \overrightarrow { y^n}&gt; +  &lt;-z \overrightarrow {1^n}, \overrightarrow a_R \circ \overrightarrow {y^n}&gt; +  &lt;\overrightarrow a_L, \space\space \overrightarrow a_R \circ \overrightarrow {y^n}&gt;\]

\[z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt;=  &lt;\overrightarrow a_L, \space\space z^2 \overrightarrow {2^n} +  z \overrightarrow {y^n} + \overrightarrow a_R \circ \overrightarrow {y^n}&gt; + &lt;-z\overrightarrow {1^n}, \overrightarrow a_R \circ \overrightarrow{y^n}&gt;\]

\[z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt;=  &lt;\overrightarrow a_L, \space\space z^2 \overrightarrow {2^n} +  z \overrightarrow {y^n} + \overrightarrow a_R \circ \overrightarrow {y^n}&gt; + &lt;-z \overrightarrow{1^n}, \overrightarrow a_R \circ \overrightarrow{y^n}&gt;\]

<p>Adding $&lt; -z \overrightarrow{1^n}, z^2 \overrightarrow{2^n } +  z\overrightarrow {y^n}&gt;$ to both sides,</p>

\[z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt; + &lt; -z\overrightarrow {1^n}, z^2 \overrightarrow{2^n } +  z\overrightarrow{y^n}&gt; =  &lt;\overrightarrow a_L, \space\space z^2 \overrightarrow{2^n } +  z\overrightarrow{y^n} + \overrightarrow a_R \circ \overrightarrow {y^n}&gt; + &lt;\overrightarrow -z\overrightarrow {1^n}, z^2 \overrightarrow{2^n } +  z\overrightarrow{y^n&gt;} + &lt;-z \overrightarrow {1^n}, \overrightarrow a_R \circ\overrightarrow{ y^n}&gt;\]

<p>The Right Hand Side of the above can be simplified as</p>

<p>RHS $  =  &lt;\overrightarrow a_L -z \overrightarrow{1^n},  \space\space \overrightarrow {y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n})+ z^2 \overrightarrow{2^n} &gt; $</p>

<p>Let’s check the Left Hand side</p>

<p>LHS = $z^2  v +  z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt; + &lt; -z\overrightarrow {1^n}, z^2 \overrightarrow{2^n } +  z\overrightarrow{y^n}&gt;$</p>

<p>All terms except the $z^2 v$ consists of either constants or $y$ and $z$ terms. $\mathcal V$ knows $y$ &amp; $z$ &amp; the constants, so let’s express it as a function $f$</p>

<p>$f(y,z) = z &lt;\overrightarrow {1^n}, \overrightarrow {y^n} &gt; + &lt; -z\overrightarrow {1^n}, z^2 \overrightarrow{2^n } +  z\overrightarrow{y^n}&gt;$</p>

<p>$f(y,z)$ can be computed by $\mathcal V$ on his own.</p>

\[z^2  v + f(y,z) = &lt;\overrightarrow a_L -z \overrightarrow{1^n},  \space\space \overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n})+ z^2 \overrightarrow{2^n }&gt;\]

<p>Let</p>

<p>$\overrightarrow {ul} = \overrightarrow a_L -z \overrightarrow{1^n}$</p>

<p>$\overrightarrow {ur} = \overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n})+ z^2 \overrightarrow{2^n }$</p>

<p>So $\mathcal P$ has to prove that</p>

<p>$&lt;\overrightarrow {ul}, \overrightarrow {ur}&gt; = z^2  v + f(y,z)$</p>

<h4 id="blinding">Blinding</h4>

<p>However, if $\mathcal P$ creates commitments to $\overrightarrow {ul}$ &amp; $\overrightarrow {ur}$ &amp; runs the Bulletproof protocol to prove the above, it wouldn’t be zero knowledge because as we noted earlier, in the Bulletproofs protocol, the commitment to the vectors $\overrightarrow m$ &amp; $\overrightarrow n$ didn’t have a Blinding factor. Hence $\mathcal P$ first blinds $\overrightarrow {ul}$ &amp; $\overrightarrow {ur}$.</p>

<p>$\mathcal P$ randomly samples 2 blinding vectors $\overrightarrow s_L$ &amp; $\overrightarrow s_R$, same size as the unblinded vectors &amp; linearly combines them with the unblinded vectors to form 2 blinded terms, $\overrightarrow a_L + \overrightarrow s_Lx$ &amp; $\overrightarrow a_R + \overrightarrow s_Rx$.</p>

<p>We replace the vectors in $\overrightarrow {ul}$ &amp; $\overrightarrow {ur}$ with the  blinded vectors. However, by doing this, they no longer remain vectors, they become  vector polynomials.</p>

<p>$\overrightarrow l(x) = \overrightarrow a_L + s_Lx -z \overrightarrow{1^n}$</p>

<p>$\overrightarrow r(x) = \overrightarrow{y^n}\circ (\overrightarrow a_R + s_Rx + z \overrightarrow{1^n})+ z^2 \overrightarrow{2^n }$</p>

<p>Let</p>

<p>$\overrightarrow l_0 = \overrightarrow a_L -z \overrightarrow{1^n}$</p>

<p>$\overrightarrow l_1 = \overrightarrow s_L$</p>

<p>So, $\overrightarrow l(x) = \overrightarrow l_0 + \overrightarrow l_1x$</p>

<p>$\overrightarrow r(x) = \overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n}) + z^2 \overrightarrow{2^n } + \overrightarrow{y^n}\circ s_Rx  $</p>

<p>$\overrightarrow r_0 = \overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n}) + z^2 \overrightarrow{2^n } $</p>

<p>$\overrightarrow r_1 = \overrightarrow{y^n}\circ s_R  $</p>

<p>So, $\overrightarrow r(x) = \overrightarrow r_0 + \overrightarrow r_1x$</p>

<p>Let $t(x) = &lt;\overrightarrow l(x), \overrightarrow r(x)&gt;$</p>

<p>(The inner product of 2 vector polynomials results in a regular polynomial.)</p>

<p>$t(x) = &lt;\overrightarrow l_0 + \overrightarrow l_1x,\overrightarrow r_0 + \overrightarrow r_1x&gt;$</p>

<p>$\qquad =&lt;\overrightarrow l_0,\overrightarrow r_0&gt; + (&lt;\overrightarrow l_0,\overrightarrow r_1&gt; + &lt;\overrightarrow l_1,\overrightarrow r_0&gt;)x + &lt;\overrightarrow l_1,\overrightarrow r_1&gt;x^2$</p>

<p>If $t(x) = t_0 + t_1x + t_2x^2$</p>

<p>$t_2 = &lt;\overrightarrow l_1,\overrightarrow r_1&gt;$</p>

<p>$t_1 = &lt;\overrightarrow l_0,\overrightarrow r_1&gt; + &lt;\overrightarrow l_1,\overrightarrow r_0&gt;$</p>

<p>$t_0 = &lt;\overrightarrow l_0,\overrightarrow r_0&gt; = &lt;\overrightarrow a_L -z \overrightarrow{1^n},\overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n}) + z^2 \overrightarrow{2^n }&gt;$</p>

<h4 id="the-proof">The Proof</h4>

<p>$\mathcal P$ uses steps similar to that used in the optimized method showed in the <a href="./#zero-knowledge-polynomial-product">Zero Knowledge Polynomial Multiplication Proof</a> section to prove that $t(x) = &lt;\overrightarrow l(x), \overrightarrow r(x)&gt;$. The Polynomials multiplied here are Vector Polynomials &amp; not regular ones &amp; hence Vector Pedersen commitments would be used. There are also other changes &amp; optimizations.</p>

<p>$\mathcal P$ needs to provide the following proofs.</p>

<p>$1)$ Evaluation Proof that $t(x) =\overrightarrow t_0 + \overrightarrow t_1x + \overrightarrow t_2x^2$</p>

<p>$2)$ Evaluation Proof of $\overrightarrow l(x)$ &amp; $\overrightarrow r(x)$</p>

<p>$3)$ Proof that $t_u = &lt;\overrightarrow l_u, \overrightarrow r_u&gt;$</p>

<p>$\mathcal P$ creates a hiding &amp; blinding commitment to $\overrightarrow a_L$ &amp; $\overrightarrow a_R$ &amp; another one to $\overrightarrow s_L$ &amp; $\overrightarrow s_R$</p>

<p>$C_a = \overrightarrow a_L \overrightarrow G + \overrightarrow a_R \overrightarrow H + b_a B $</p>

<p>$C_s = \overrightarrow s_L \overrightarrow G + \overrightarrow s_R \overrightarrow H + b_s B $</p>

<p>She creates commitments to $t_1$ &amp; $t_2$</p>

<p>$C_{t_1} = \overrightarrow t_1 \overrightarrow G + b_{t_1} B$</p>

<p>$C_{t_2} = \overrightarrow t_2 \overrightarrow G + b_{t_2} B$</p>

<p>$\mathcal P$ sends $C_a, C_s, C_{t_1}$ &amp; $C_{t_2}$ to $\mathcal V$. $\mathcal V$ of the Monero Transaction already has the <a href="/Monero/#amount-commitments">amount commitment</a> $C_v$ of the value ($v$) whose range we are proving</p>

<p>$C_v = v G + b_vB $</p>

<p>$\mathcal V$ samples random $u$ &amp; sends it to $\mathcal P$.</p>

<p>$\mathcal P$ evaluates $\overrightarrow l_u = \overrightarrow l(x=u), \overrightarrow r_u = \overrightarrow r(x=u)$ &amp; $ t_u = t(x=u)$ &amp; computes $b_{lr} = b_a + ub_s$ and $b_t = z^2 b_v + b_1u + b_2u^2$.</p>

<p>$\mathcal P$ sends $t_u, b_{lr}$ &amp; $b_t$ to $\mathcal V$.</p>

<p>We write the evaluation of $l(x)$ &amp; $r(x)$ at $u$ as $\overrightarrow l_u$ &amp; $\overrightarrow r_u$ respectively &amp; not as $l_u$ &amp; $r_u$ because as we noted earlier, the evaluation of a vector polynomial is a vector &amp; not a scalar.</p>

<h5 id="evaluation-proof-for-tx">Evaluation Proof for $t(x)$</h5>

<p>$\mathcal P$ has sent commitments $C_{t_1}, C_{t_2}$ &amp; also $b_t, t_u$.</p>

<p>$\mathcal V$ can compute a commitment to $t_u$ himself</p>

<p>$C_{t_u} = t_uG + b_tB$</p>

<p>$\mathcal V$ checks if</p>

<p>$C_{t_u} \stackrel {?}{=} z^2C_v + f(y,z)G + uC_{t_1} + u^2C_{t_2}$</p>

<p>$\mathcal V$ rejects the proof if the equality doesn’t check out.</p>

<h5 id="proof-of-correctness-of-overrightarrow-lx--overrightarrow-lx--that-t_u--overrightarrow-lx-overrightarrow-rx">Proof of correctness of $\overrightarrow l(x)$ &amp; $\overrightarrow l(x)$ &amp; that $&lt;t_u = \overrightarrow l(x), \overrightarrow r(x)&gt;$</h5>

<p>Like in the section about the optimized proof for <a href="#zero-knowledge-polynomial-product-proof">Regular Polynomial Products</a>, $\mathcal V$ has to construct $S = C_0 + uC_1$ &amp; verify it ($C_0$ is a commitment to the constant terms of both the left &amp; right vector polynomials &amp; $C_1$ to the linear terms). However, unlike the earlier case, he doesn’t already have the full $C_0$ or $C_1$ but only a commitment of some of the terms in them through $C_a$ &amp; $C_s$. But he can create the commitments to the remaining terms himself so that $\mathcal P$ doesn’t have to send those.</p>

<p>To enable $\mathcal V$ to compute commitments to some terms above like $(\overrightarrow {y^n} o \overrightarrow a_R)$ by himself, Bulletproofs uses a trick.</p>

<p>$\mathcal V$ creates a new vector of generators
$\overrightarrow {H’} = \frac {\overrightarrow H}{\overrightarrow {y^n}}  = [\frac {H_0}{y^0}, \frac {H_1}{y^1}, \frac {H_2}{y^2}, …]$</p>

<p>So now, $\overrightarrow H = \overrightarrow {y^n} \overrightarrow {H’}$.</p>

<p>Substituting the above into $C_a$ &amp; $C_s$,  we get</p>

<p>$C_a = \overrightarrow a_L G + \overrightarrow (a_R\space o\space \overrightarrow {y^n}) \overrightarrow {H’} + b_aB$</p>

<p>$C_s = \overrightarrow s_L \overrightarrow G + (\overrightarrow s_R \circ \overrightarrow {y^n})\overrightarrow {H’}-b_sB$</p>

<p>So,</p>

<p>$C_a - b_aB =  \overrightarrow a_L G + \overrightarrow (a_R\space o\space \overrightarrow {y^n}) \overrightarrow {H’}$</p>

<p>$C_s -b_sB = \overrightarrow s_L \overrightarrow G + (\overrightarrow s_R \circ \overrightarrow {y^n})\overrightarrow {H’}$</p>

<p>Now $\mathcal V$ constructs a commitment for $C_0$ &amp; $C_1$ with bases $\overrightarrow G$ &amp; $\overrightarrow {H’}$.</p>

<p>$C_0 = \overrightarrow a_L \overrightarrow G - z\overrightarrow{1^n} + (\overrightarrow a_R \circ \overrightarrow {y^n})\overrightarrow {H’} + (z\overrightarrow {1^n}\circ \overrightarrow {y^n})\overrightarrow {H’} + z^2 \overrightarrow{2^n } \overrightarrow {H’}$</p>

<p>$C_1 = \overrightarrow s_L \overrightarrow G  +  ( \overrightarrow s_R \circ  \overrightarrow{y^n} ) \overrightarrow {H’}$</p>

<p>$\mathcal V$ computes $S = C_0 + uC_1$.</p>

<p>$S = C_0 + uC_1 = \overrightarrow a_L \overrightarrow G - z\overrightarrow{1^n} + (\overrightarrow a_R \circ \overrightarrow {y^n})\overrightarrow {H’} + (z\overrightarrow {1^n}\circ \overrightarrow {y^n})\overrightarrow H + z^2 \overrightarrow{2^n } \overrightarrow H + u(\overrightarrow s_L \overrightarrow G  +  ( \overrightarrow s_R \circ  \overrightarrow{y^n} ) \overrightarrow H$</p>

<p>Rearranging and also substituting $z\overrightarrow {1^n}\circ \overrightarrow {y^n} = z\overrightarrow{y^n}$</p>

<p>$S = (\overrightarrow a_L \overrightarrow G + (\overrightarrow a_R \circ \overrightarrow {y^n})\overrightarrow {H’}) - z\overrightarrow{1^n} + z\overrightarrow{y^n}\overrightarrow {H’} + z^2 \overrightarrow{2^n } \overrightarrow {H’} + u(\overrightarrow s_L \overrightarrow G  +  ( \overrightarrow s_R \circ  \overrightarrow{y^n} ) \overrightarrow {H’})$</p>

<p>Substituting $C_a - b_aB$ &amp; $C_s -b_sB$ into the above</p>

<p>$S = C_a + uC_s - (b_a + ub_s)B - z\overrightarrow{1^n} + z\overrightarrow{y^n}\overrightarrow {H’} + z^2 \overrightarrow{2^n } \overrightarrow {H’}$</p>

<p>$\mathcal V$ knows $C_a, C_s$ &amp; $\mathcal P$ has sent him $b_{lr} = b_a + ub_s$. The remaining terms can also be computed by $\mathcal V$ because he knows $z$ &amp; $y$. So $\mathcal V$ computes $S$.</p>

<p>As we saw in the optimized method showed in the <a href="./#zero-knowledge-polynomial-product">Zero Knowledge Polynomial Multiplication Proof</a> section, $S = C_{l(x=u)} + C_{r(x=u)}$.</p>

<p>So, $S$ is a commitment to $\overrightarrow l_u$ &amp; $\overrightarrow r_u$.</p>

<p>$\mathcal V$ also sends a random $r$ &amp; computes a new generator $U = rV$.</p>

<p>$\mathcal P$ &amp; $\mathcal V$  construct</p>

<p>$P = S + t_uU$</p>

<p>i.e.</p>

<p>$P = \overrightarrow l_u \overrightarrow G + \overrightarrow r_u \overrightarrow H + t_uU$</p>

<p>So $\mathcal P$ can use the Bulletproofs protocol to prove to $\mathcal V$ that she knows a commitment to $\overrightarrow l_u$ &amp; $\overrightarrow r_u$ and that $t_u = &lt;\overrightarrow l_u, \overrightarrow r_u&gt;$.</p>

<p>The simple proof for $t_u = &lt;\overrightarrow l_u, \overrightarrow r_u&gt;$ is to send $t_u$, $\overrightarrow l_u$ &amp; $\overrightarrow r_u$ to $\mathcal V$ &amp; $\mathcal V$ checks if $t_u \stackrel {?}{=} &lt;\overrightarrow l_u, \overrightarrow l_r&gt;$. However, each of the vectors contains $N$ elements i.e. $2N$ elements would need to be sent by $\mathcal P$ to $\mathcal V$, so it won’t be a succinct proof. So $\mathcal P$ doesn’t send the vectors, but uses Bulletproofs which is logarithmic.</p>

<p>$\mathcal P$ has proved that $t(x) = t_0 + t_1x + t_2x^2 = &lt;\overrightarrow l(x), \overrightarrow r(x)&gt;$. If 2 polynomials are equal, it means each of their co-efficients is equal.</p>

<p>The constant co-efficient of $t(x)$ is equal to $z^2 v + f(y,z) $. The constant co-efficient of $
&lt;\overrightarrow l(x), \overrightarrow r(x) &gt;$ is $&lt;\overrightarrow l_0,\overrightarrow r_0&gt; = &lt;\overrightarrow a_L -z \overrightarrow{1^n},\overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n}) + z^2 \overrightarrow{2^n }&gt;$</p>

<p>So, this proves that</p>

<p>$z^2 v + f(y,z) = &lt;\overrightarrow l_0,\overrightarrow r_0&gt; = &lt;\overrightarrow a_L -z \overrightarrow{1^n},\overrightarrow{y^n}\circ (\overrightarrow a_R + z \overrightarrow{1^n}) + z^2 \overrightarrow{2^n }&gt;$</p>

<p>Which is what we set out to prove. This concludes the Range Proofs for Monero.</p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FBulletproofs%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Privacy and Anonymity in Monero</title><link href="https://risencrypto.github.io/Monero/" rel="alternate" type="text/html" title="Privacy and Anonymity in Monero" /><published>2024-12-04T00:00:00+00:00</published><updated>2024-12-04T00:00:00+00:00</updated><id>https://risencrypto.github.io/Monero</id><content type="html" xml:base="https://risencrypto.github.io/Monero/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<h3 id="prerequisites-primitives--notations">Prerequisites, Primitives &amp; Notations</h3>

<h4 id="bitcoin-transactions">Bitcoin Transactions</h4>
<p>Before getting into Monero, let’s first see how Bitcoin (BTC) transactions work.</p>

<p>In BTC, every wallet has an Elliptic Curve Public-Private Key Pair. Let $G$ be the Generator of the Elliptic Curve used by BTC. If $x$ is someone’s private key, then $P = xG$ is his public key.</p>

<p>Let’s dive into a transaction between Alice &amp; Bob. Alice rents an apartment from Bob &amp; wants to send 0.015 BTC as rent to Bob. Though we talk about coins, there really isn’t any coin being passed around with each transaction. Everyone other than miners spend what is called as Unspent Transaction Output (UTXO) - i.e. everyone has BTC because someone else sent it to them in a transaction. They can spend only their UTXOs. So if Alice wants to send some money to Bob, she has to have UTXO(s) which was sent to her by someone else. Just today,  Alice was paid 0.1 BTC as salary by her employer - so she has a UTXO of 0.1 BTC &amp; she hasn’t spent any of it yet. She creates a new transaction where she sends 0.015 BTC to Bob. However, she cannot only spend part of a UTXO, she has to spend it fully, so she also sends the remaining change to herself as part of the same transaction. So she sends 0.0845 BTC to herself &amp; 0.015 BTC to Bob. The balance (0.1 - 0.0845 - 0.015 = 0.0005) is automatically assumed to be the mining fee. Alice locks Bob’s output (i.e. the 0.015 BTC she sent to Bob) with Bob’s public key &amp; locks her own output (0.0845 BTC) with her own public key. When Bob wants to spend his output, he has to show proof of possession of the private key corresponding to the public key which locks that output. Alice’s employer had locked Alice’s output of the salary transaction with Alice’s Public Key. So for Alice’s spend to be valid, Alice needs to provide proof that possession of the corresponding private key. Alice takes a modified version of the transaction &amp; signs it with her private key &amp; attaches it to the transaction - the signature is her proof of possession of the private key. Any verifier (the nodes) can verify the signature was indeed created by the actual owner of the UTXO.</p>

<p>Few more things are verified</p>
<ul>
  <li>
    <p>is the sum of inputs is greater than sum of the outputs? Alice’s transaction has only one input (0.1 BTC) &amp; has 2 outputs (0.015 BTC &amp; 0.0845 BTC). The verifiers verify that $0.1 \stackrel {?}{&gt;} 0.015 + 0.0845$</p>
  </li>
  <li>
    <p>Was this really a Unspent Transaction Output - i.e. has already spent the BTC she got as salary earlier? A UTXO is defined by a Transaction Id (TxId) &amp; an output Index for each output. Each node in the blockchain maintains a list of UTXOs &amp; updates it whenever a new block is added to the blockchain. They go through each transaction in a newly minted block &amp; remove all the inputs in each transaction from their list &amp; add all the outputs in each transaction to their list of UTXOs. If any of the input UTXOs do not exist in their list, it means that particular UTXO has already been spent &amp; they reject the block. This is how double spending is prevented in a BTC Blockchain.</p>
  </li>
</ul>

<h4 id="hash-function-notations-used-in-this-post">Hash function Notations used in this post</h4>

<ul>
  <li>
    <p>$H()$ denotes a Hash function like Keccak/SHA3.</p>
  </li>
  <li>
    <p>$H_s()$ denotes a Hash to Scalar function. This function may call a Hash function like $H()$ &amp; then convert the output hash to an integer and return the integer which to be used as a scalar.</p>
  </li>
  <li>
    <p>$H_p()$ denotes a Hash to Point function. This function may call a Hash function like $H()$ &amp; after converting the output to an integer, it maps the integer to an Elliptic Curve point &amp; returns the point.</p>
  </li>
  <li>
    <p>When we write something like $H(inp_1, inp_2, …, inp_n)$, it usually means that these inputs are first encoded as byte arrays &amp; then concatenated before passing it as a single input to the hash function.</p>
  </li>
  <li>
    <p>In my examples, I use <code class="language-plaintext highlighter-rouge">sha3_256</code> hash function from <code class="language-plaintext highlighter-rouge">hashlib</code> (Monero uses a variant of SHA-3 named Keccak256 which is similar except that it uses different padding).</p>
  </li>
</ul>

<h4 id="pedersen-commitments">Pedersen Commitments</h4>

<p>You can look up just the <a href="/Kate/#what-is-a-commitment">What is a commitment</a> part of this linked post to understand what is a commitment.</p>

<p>Alice claims that she can predict the winner of a horse race in which 12 horses are competing. She thinks Horse #$5$ will win the race. But she doesn’t want to tell Bob before the race is over. However, if she tells Bob only after the race is over, then he obviously won’t believe that she predicted it before hand. Hence she commits to the number before the race &amp; opens the commitment after the race is over to prove that she did predict it correctly.</p>

<p>Let’s try to build a simple commitment scheme from scratch to help Alice. A hash function $H$ can work as a commitment. She can send the hash of $5$ i.e. $H(5)$ to Bob as a commitment. After the race is over &amp; Horse #5 has won the race, Alice tells Bob that this was the same as what she predicted. Bob can hash the number $5$ himself &amp; compare it to hash sent by Alice beforehand to check if she had in fact predicted it correctly. Such a commitment though binding isn’t hiding. Since there are only 12 horses - even before the race is complete, Bob can hash all numbers from 1 to 12 &amp; check which hash matches to find the horse chosen by Alice. Also, in the next race, if Alice again thinks Horse #5 will win &amp; sends $H(5)$ as the commitment, Bob can compare with the earlier commitment &amp; figure out that Alice has sent a commitment to 5.</p>

<p>Instead, Alice samples a random number $b$ called as a blinding factor &amp; sends $H(5, b)$ &amp; sends it to Bob (as mentioned earlier, both $5$ &amp; $b$ will be converted to bytes &amp; concatenated before hashing). Since $b$ can be a huge number, Bob can’t brute force all combinations from 1 to 12 to figure out which was the number chosen by Alice. Once the race is over, Alice can disclose $5$ &amp; $b$ to Bob &amp; he can compute $H(5, b)$ to check if she had indeed chosen $5$. And for every new commitment, Alice choses a new blinding factor even if she choses 5 in a future race, the commitment won’t reveal the value to Bob till she reveals the new blinding factor.</p>

<p>A function $C(y) = y G$ can also work as commmitment for the number $y$ - here $G$ is a generator of an Elliptic Curve where the discrete log problem is hard.</p>

<p>Again, this is binding but not hiding. The trick of $C(5, b)$ will not work to fix this because unlike the SHA-3 Hash function, this is an algebraic function- converting to bytes &amp; concatenating makes no sense here &amp; just adding up the 2 numbers will not be Binding. Let’s say Alice had sampled $b = 25$ &amp; sent $C(5, 25)$ i.e. $C(30)$ to Bob as the commitment. If Horse 7 won instead of 5, even then Alice can be dishonest and say her blinding factor was $b=23$ &amp; claim that she did predict correctly.</p>

<p>Pedersen Commitments solves this by having 2 Generators $G$ &amp; $B$ such that the relation between $B$ &amp; $G$ isn’t known - i.e. nobody knows an $n$ such that $B = nG$. The 2nd generator $B$ is used for the blinding factor. Monero uses $B = H_p(G)$ to compute a 2nd generator which satisfies this requirement.</p>

<p>A Pedersen commitment for $u$ is defined as</p>

<p>$C_u = u G + b B $</p>

<p>One very useful quality of a Pedersen commitment is that it’s additively homomorphic. If we create 2 commitments - one for the number 5 &amp; the other for number 12.</p>

<p>$C_1 = 5G + b_1B$</p>

<p>$C_2 = 12G + b_2G$</p>

<p>Then, $C_3 = C_1 + C_2 = 17G + (b_1 + b_2)B$</p>

<p>$C_3$ automatically becomes the commitment for 17 with a blinding factor of $b_1 + b_2$</p>

<h4 id="schnorr-signature">Schnorr Signature</h4>

<p>Let’s first look at the Schnorr Proof of Possession of a Private Key without involving messages.</p>

<p>Let $G$ be the Generator of an Elliptic Curve. Alice wants to prove that she knows a private key $x$ such that her Public Key $P$ is $P = xG$.</p>

<p>Alice samples a random $r$ &amp; computes $R = rG$ &amp; sends $R$ to Bob.</p>

<p>Bob samples a random $c$ &amp; sends it to Alice. Alice computes $s = r - cx$ &amp; sends $s$ to Bob.</p>

<p>Bob checks if $sG \stackrel {?}{=} R -cP$ - if it is, then he is convinced that Alice is in possession of private key corresponding to $P$.</p>

<p>Why does this proof work?</p>

<p>$s = r - cx$</p>

<p>Multiply both sides by $G$</p>

<p>$sG = rG - cxG$</p>

<p>But $R = rG$ and $P = xG$.</p>

<p>So $sG = R -cP$</p>

<p>If Alice knows $c$ before she choses $R$, then she can easily chose a random $s$ &amp; an $R$ such that $R = sG + cP$. That’s why for this proof to be sound, Bob should send $c$ only after Alice has sent him $R$. The problem with this however is that it is interactive. But, it can easily be made non-interactive by using Fiat Shamir. Instead of Bob sending $c$, Alice herself computes $c = H_s(R)$. Since $c$ is computed from $R$, Alice cannot choose a $R$ beforehand such that $R = sG + cP$, so the proof is sound.</p>

<p>Schnorr Signature of a message $M$ is the same except $c$ is computed as</p>

<p>$c = H_s(M, R)$</p>

<p>Signing a message also provides proof of possession of the private key used to sign the message.</p>

<p>Below is a sagemath implementation. I use an insecure toy Elliptic Curve for all the examples in this for ease of understanding.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">import</span> <span class="n">hashlib</span>

<span class="nb">p</span> <span class="o">=</span> <span class="mi">7919</span>
<span class="no">Fp</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="nb">p</span><span class="p">)</span>
<span class="n">a</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">6628</span><span class="p">)</span>
<span class="n">b</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">1900</span><span class="p">)</span>
<span class="no">Es</span> <span class="o">=</span> <span class="no">EllipticCurve</span><span class="p">(</span><span class="no">Fp</span><span class="p">,</span> <span class="p">[</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="p">])</span>
<span class="no">G</span> <span class="o">=</span> <span class="no">Es</span><span class="p">(</span><span class="mi">1892</span><span class="p">,</span> <span class="mi">4372</span><span class="p">)</span> <span class="c1"># Generator</span>
<span class="n">q</span> <span class="o">=</span> <span class="no">G</span><span class="p">.</span><span class="nf">order</span><span class="p">()</span>
<span class="no">Fq</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">point_to_bytes</span><span class="p">(</span><span class="n">pt_</span><span class="p">):</span>
    <span class="k">if</span><span class="p">(</span><span class="n">pt_</span> <span class="o">==</span> <span class="mi">0</span><span class="p">):</span>
        <span class="k">return</span> <span class="s2">"None,None"</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="s2">"utf8"</span><span class="p">)</span>

    <span class="n">bx</span> <span class="o">=</span>  <span class="n">int</span><span class="p">(</span><span class="n">pt_</span><span class="p">.</span><span class="nf">x</span><span class="p">()).</span><span class="nf">to_bytes</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>
    <span class="n">by</span> <span class="o">=</span>  <span class="n">int</span><span class="p">(</span><span class="n">pt_</span><span class="p">.</span><span class="nf">y</span><span class="p">()).</span><span class="nf">to_bytes</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">bx</span> <span class="o">+</span> <span class="n">by</span>

<span class="k">def</span> <span class="nf">bytes_to_point</span><span class="p">(</span><span class="n">bpt_</span><span class="p">):</span>
    <span class="k">if</span><span class="p">(</span><span class="n">bpt_</span> <span class="o">==</span> <span class="n">b</span><span class="s1">'None,None'</span><span class="p">):</span>
        <span class="k">return</span> <span class="no">Es</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
       
    <span class="n">x</span> <span class="o">=</span> <span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">bpt_</span><span class="p">[:</span><span class="mi">32</span><span class="p">],</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>
    <span class="n">y</span> <span class="o">=</span> <span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">bpt_</span><span class="p">[</span><span class="mi">32</span><span class="p">:],</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>

    <span class="k">return</span> <span class="no">Es</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">pt_</span><span class="p">):</span>
    <span class="n">h</span> <span class="o">=</span>  <span class="n">hashlib</span><span class="p">.</span><span class="nf">sha3_256</span><span class="p">(</span><span class="n">msg_</span> <span class="o">+</span> <span class="n">point_to_bytes</span><span class="p">(</span><span class="n">pt_</span><span class="p">)).</span><span class="nf">digest</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">schnorr_sign</span><span class="p">(</span><span class="n">x_</span><span class="p">,</span> <span class="n">msg_</span><span class="p">):</span>
    <span class="n">r</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>
    <span class="no">R</span> <span class="o">=</span> <span class="n">r</span> <span class="o">*</span> <span class="no">G</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span><span class="no">R</span><span class="p">)</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">int</span><span class="p">(</span><span class="n">r</span> <span class="o">-</span> <span class="n">c</span><span class="o">*</span><span class="n">x_</span><span class="p">).</span><span class="nf">to_bytes</span><span class="p">(</span><span class="mi">32</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>
    <span class="no">Rb</span> <span class="o">=</span> <span class="n">point_to_bytes</span><span class="p">(</span><span class="no">R</span><span class="p">)</span>
    <span class="n">sig</span> <span class="o">=</span> <span class="p">(</span><span class="no">Rb</span><span class="p">,</span> <span class="n">s</span><span class="p">)</span>

    <span class="k">return</span> <span class="n">sig</span>

<span class="k">def</span> <span class="nf">schnorr_verify</span><span class="p">(</span><span class="no">Pub_</span><span class="p">,</span> <span class="n">sig_</span><span class="p">,</span> <span class="n">msg_</span><span class="p">):</span>
    <span class="no">R</span> <span class="o">=</span> <span class="n">bytes_to_point</span><span class="p">(</span><span class="n">sig_</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">sig_</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">R</span><span class="p">)</span>
    <span class="n">left</span> <span class="o">=</span> <span class="n">s</span><span class="o">*</span><span class="no">G</span>
    <span class="n">right</span> <span class="o">=</span> <span class="no">R</span> <span class="o">-</span> <span class="n">c</span><span class="o">*</span><span class="no">Pub_</span>
    <span class="k">return</span><span class="p">(</span><span class="n">left</span> <span class="o">==</span> <span class="n">right</span><span class="p">)</span> 

<span class="n">x</span> <span class="o">=</span> <span class="n">int</span><span class="p">(</span><span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">())</span> <span class="c1">#Private Key</span>
<span class="no">Pub</span> <span class="o">=</span> <span class="n">x</span><span class="o">*</span><span class="no">G</span> <span class="c1">#Public Key</span>

<span class="n">msg</span> <span class="o">=</span> <span class="s1">'HelloWorld'</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="s1">'utf8'</span><span class="p">)</span> <span class="c1">#Message to Sign</span>

<span class="n">sig</span> <span class="o">=</span> <span class="n">schnorr_sign</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span>

<span class="k">if</span><span class="p">(</span><span class="n">schnorr_verify</span><span class="p">(</span><span class="no">Pub</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="n">msg</span><span class="p">)):</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">"Signature Verified"</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Note:</strong></p>
<ul>
  <li>The Discrete Log problem isn’t hard in this Curve like it should be.</li>
  <li>For simplicity, I don’t compress Elliptic Curve Points like Monero does.</li>
  <li>Protocols/methods I use for converting inputs before hashing may not be same used by Monero - but it’s not relevant for  understanding the cryptographic concepts.</li>
  <li>Many Schnorr implementations use  $s = r + cx$ but Monero uses $s = r - cx$ (and also adjusts verification accordingly) - not much of a difference between the two ways - except that the first is optimised for signing &amp; Monero’s way is optimised for verification. On a blockchain, each signing is verified many, many times &amp; hence it may help to optimise verification over signing.</li>
</ul>

<h4 id="ring-signature">Ring Signature</h4>
<p>Consider a group/ring of Key Pairs which are unrelated &amp; belong to different people. The Owner of one of the Pairs in the Ring wants to sign a message in a way that it’s possible for a verifier to verify that one of the ring
members signed the message without being able to determine which of the members did it. For constructing a ring signature like this, the Signer uses her own Public-Private keypair, but only the Public Keys of the others. The other members of the Ring aren’t involved in the signing operation. Here, I discuss Ring Signatures where the underlying signature scheme is a  Schnorr Signature.</p>

<p><strong>Signing:</strong></p>

<p>Let’s consider a Ring of Public Keys $\lbrace P_0, P_1, …, P_k, …, P_{n-1} \rbrace$</p>

<p>One of these keys $P_k$ is Alice’s Public key - i.e. Alice knows a private key $x$ such that $P_k = xG$</p>

<ul>
  <li>Alice randomly samples $r$ and computes $R_k= rG$</li>
  <li>Alice computes $c_{k+1} = H_s(M, R_k)$</li>
  <li>Alices samples random $s_{k+1}$ &amp; computes $R_{k+1} = s_{k+1}G + c_{k+1}P_{k+1}$</li>
  <li>
    <p>Alice computes $c_{k+2} = H_s(M, R_{k+1} )$</p>
  </li>
  <li>
    <p>Alice then samples $s_{k+2}$ &amp; computes $R_{k+2} = s_{k+2}G + c_{k+2}P_{k+2}$ &amp; $c_{k+3} = H_s(M, R_{k+2} )$</p>
  </li>
  <li>
    <p>Alice continues this all the way to the $n^{th}$ element where she samples a random $s_{n-1}$, computes $R_{n-1}$ &amp; computes $c_0 = H_s(M, R_{n-1})$</p>
  </li>
  <li>
    <p>Alice samples $s_0$, computes $c_1$, continues all the way to sampling $s_{k-1}$ &amp; computing $c_k = H_s(M, R_{k-1})$</p>
  </li>
  <li>
    <p>Alice has sampled random $s_0$ to $s_{k-1}$ &amp; $s_{k+1}$ to $s_{n-1}$ except for $s_k$</p>
  </li>
  <li>Alice sets $s_k = r_k - c_kx$</li>
</ul>

<p>The signature resulting from this operation is $\lbrace c_0, s_0, s_1, …, s_{n-1}\rbrace$</p>

<p><strong>Verification:</strong></p>

<ul>
  <li>Verifier computes $R_0 = s_0G + c_0P_0$</li>
  <li>Verifier computes $c_1 = H_s(M, R_0)$</li>
  <li>Verifier computes $R_1 = s_1G + c_1P_1$</li>
  <li>
    <p>Verifier computes $c_2 = H_s(M, R_1)$</p>
  </li>
  <li>Verifier continues all the way to $c_{n-1} = H_s(M, R_{n-2})$ &amp; $R_{n-1} = s_{n-1}G + c_{n-1}P_{n-1}$</li>
  <li>Then $c_0 = H_s(M, R_{n-1} )$</li>
</ul>

<p>If the $c_0$ computed by the verifier equals the $c_0$ sent by the signer, then it means the signature has verified.</p>

<p><strong>Why does it work?</strong></p>

<p>The Signer closed the loop with</p>

<p>$s_k = r - c_kx$</p>

<p>So $c_{k+1} = H_s(M, rG) $</p>

<p>$\qquad \quad = H_s(M, (s_k + c_kx)G$</p>

<p>$\qquad \quad = H_s(M, s_kG + c_kxG)$</p>

<p>But $xG = P_k$</p>

<p>So $c_{k+1} = H_s(M, s_kG + c_kP_k)$</p>

<p>Which is a similar structure as the other $c$’s. And this closes the loop.</p>

<p>A sagemath example</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">ring_sign</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">Pubs_</span><span class="p">,</span> <span class="n">s_</span><span class="p">,</span> <span class="n">k_</span><span class="p">,</span> <span class="n">x_</span><span class="p">):</span>
    <span class="n">sc</span> <span class="o">=</span> <span class="n">s_</span><span class="p">.</span><span class="nf">copy</span><span class="p">()</span>
    <span class="n">r</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">r</span><span class="o">*</span><span class="no">G</span><span class="p">)</span>
    
    <span class="n">c0</span><span class="o">=</span><span class="n">c</span>

    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">):</span>
        <span class="n">idx</span> <span class="o">=</span> <span class="p">(</span><span class="n">i</span> <span class="o">+</span> <span class="n">k_</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="n">n</span>
        <span class="no">R</span> <span class="o">=</span> <span class="n">sc</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span><span class="o">*</span><span class="no">G</span> <span class="o">+</span> <span class="n">c</span><span class="o">*</span><span class="no">Pubs_</span><span class="p">[</span><span class="n">idx</span><span class="p">]</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">R</span><span class="p">)</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">idx</span> <span class="o">==</span> <span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)):</span>
            <span class="n">c0</span> <span class="o">=</span> <span class="n">c</span>

    <span class="c1"># Overwite the k'th s with a computed one</span>
    <span class="n">sc</span><span class="p">[</span><span class="n">k_</span><span class="p">]</span> <span class="o">=</span> <span class="n">r</span> <span class="o">-</span> <span class="n">c</span><span class="o">*</span><span class="n">x_</span>
    
    <span class="k">return</span> <span class="p">(</span><span class="n">c0</span><span class="p">,</span><span class="n">sc</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">sig_verify</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">sig_</span><span class="p">,</span> <span class="no">Pubs_</span><span class="p">):</span>
    <span class="no">C</span> <span class="o">=</span> <span class="n">sig_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">sig_</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">G</span> <span class="o">+</span> <span class="no">C</span><span class="o">*</span><span class="no">Pubs_</span><span class="p">[</span><span class="n">i</span><span class="p">])</span>
        <span class="no">C</span> <span class="o">=</span> <span class="n">c</span>
    
    <span class="k">return</span> <span class="p">(</span><span class="n">sig</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">c</span><span class="p">)</span>   

<span class="c1"># Main</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># Total Number of Public Keys used by Signer including her own</span>
<span class="n">k</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># The index position of Signer's Public Key in the List of Public Keys</span>

<span class="c1"># Generate the main Public/Private Key Pair for the signer</span>
<span class="n">x</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>
<span class="no">P</span> <span class="o">=</span> <span class="n">x</span><span class="o">*</span><span class="no">G</span>

<span class="no">Pubs</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># List of Public Keys</span>
<span class="n">s</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># List of Randomly sampled s's</span>

<span class="c1"># We generate n random Public Key. We also sample n s's</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
    <span class="no">Pubs</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span><span class="o">*</span><span class="no">G</span><span class="p">)</span>
    <span class="n">s</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">())</span>

<span class="c1"># Overwrite the k'th element with the Signer's Public Key</span>
<span class="no">Pubs</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="no">P</span>

<span class="n">msg</span> <span class="o">=</span> <span class="s1">'HelloWorld'</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="s1">'utf8'</span><span class="p">)</span>

<span class="n">sig</span> <span class="o">=</span> <span class="n">ring_sign</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="no">Pubs</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">k</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>

<span class="k">if</span> <span class="n">sig_verify</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="no">Pubs</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">"Signature Verified"</span><span class="p">)</span>
</code></pre></div></div>

<p><strong>Ring Signature with multiple private keys</strong></p>

<p>What if a person has multiple Private Keys &amp; wants to do ring signatures proving proof of possesion of all of them? One way is to do multiple rings, one for each private key - i.e. let’s say you have 2 private keys, you create 2 rings each having it’s own dummy public keys. And create 2 separate ring signatures.</p>

<p>However, it’s also possible to create just 1 signature which proves possession of multiple keys owned by the same person.</p>

<p>Signer has $m$ private keys $ \lbrace x_0, …, x_{m-1}\rbrace$. For each of the $m$ private keys, he collects $n-1$ dummy Public Keys (whose Private Keys he doesn’t know) and creates $m$ rings each with $n$ Public Keys</p>

<p>Let’s consider an example of 3 Private Keys ($m = 3$) &amp; a ring of 5 for each ($n=5$). Let’s assume the signer’s Public Key is in Column $k = 2$ (3rd column considering 0 based indexing) of the below matrix</p>

\[\left[
\begin{matrix}
&amp;             &amp;Signer\\
P_{0,4}&amp;P_{0,1}&amp;||P_{0,2}||&amp; P_{0,3}&amp; P_{0,4}\\
P_{1,0}&amp;P_{1,1}&amp; ||P_{1,2}||&amp; P_{1,3}&amp; P_{1,4}\\
P_{2,0}&amp;P_{2,1}&amp; ||P_{2,2}||&amp; P_{2,3}&amp; P_{2,4}\\
\end{matrix}
\right]\]

<p>The Signer knows Private Keys $x_0, x_1$ &amp; $x_2$ corresponding to public keys $P_{0,2}, P_{1,2}$ &amp; $P_{2,2}$ the remaining Public Keys in each row aren’t his, so he doesn’t know the Private Keys corresponding to them</p>

<ul>
  <li>
    <p>Alice samples a random $r_i$ &amp; computes $R_{i,k} = r_iG$ for all $i \in \lbrace 0, …, m-1 \rbrace$</p>
  </li>
  <li>
    <p>Alice computes $c_{k+1} = H_s(M, R_{0,k},R_{1,k}, … , R_{m-1,k})$</p>
  </li>
  <li>Alices samples a random $s_{i,{k+1}}$ &amp; computes $R_{i,k+1} = s_{i,k+1}G + c_{k+1}P_{i,k+1}$  for all $i \in \lbrace 0, …, m-1 \rbrace$</li>
  <li>
    <p>Alice computes $c_{k+2} = H_s(M, R_{0,k+1},R_{1,k+1}, … , R_{m-1,k+1})$</p>
  </li>
  <li>
    <p>Alice continues this all the way to the $n^{th}$ key where she samples a random $i, s_{n-1}$ &amp;  computes $R_{i,n-1}$ similarly for all $i \in \lbrace 0, …, m-1 \rbrace$</p>
  </li>
  <li>
    <p>Alice computes $c_0 = H_s(M, R_{0,n-1},R_{1,n-1}, … , R_{m-1,n-1})$</p>
  </li>
  <li>Alice continues the same all the way upto sampling $s_{i, k-1}$ for all $i \in \lbrace 0, …, m-1 \rbrace$ &amp; computes $c_k$</li>
  <li>For all $i \in \lbrace 0, …, m-1 \rbrace$, Alice sets
$s_{i,k} = r_i - c_k x_i$</li>
</ul>

<p>The signature resulting from this operation is $\lbrace c_0, s_{0,0}, s_{0,1},…, s_{0,n-1}, …, s_{m-1,0}, s_{m-1,1},…, s_{m-1,n-1} \rbrace$</p>

<p><strong>Verification:</strong></p>

<ul>
  <li>Verifier computes $R_{i,0} = s_{i,0}G + c_{0}P_{i,0}$  for all $i \in \lbrace 0, …, m-1 \rbrace$</li>
  <li>Verifier computes $c_1 = H_s(M, R_{0,0},R_{1,0}, … , R_{m-1,0})$</li>
  <li>Verifier computes for $c_2, c_3$ similarly all the way till she computes</li>
</ul>

<p>$\qquad \qquad c_0 = H_s(M, R_{0,n-1},R_{1,n-1}, … , R_{m-1,n-1})$</p>

<p>If the computed $c_0$ equals the $c_0$ sent by the signer, then it means the signature is verified.</p>

<h4 id="elliptic-curve-diffie-hellman">Elliptic Curve Diffie Hellman</h4>

<p>This post on <a href="/CofactorClearing/#cofactor-clearing">Cofactor Clearing</a> describes Elliptic Curve Diffie Hellman &amp; Cofactor Clearing.</p>

<p>Since Monero uses a Composite Order Curve with a cofactor of $8$,  Monero multiplies by $8$ during Diffie Hellman for Cofactor Clearing. Since our examples use a Prime Order Curve, we don’t do Cofactor Clearing in our examples.</p>

<p><em>This completes the pre-requisites/primitives.</em></p>

<h3 id="monero-privacy-and-anonymity">Monero Privacy and Anonymity</h3>

<p>Bitcoin isn’t anonymous and there is very little privacy. If you have ever sent BTC to Alice, you would know her BTC address. You can trawl the ledger &amp; check how many UTXOs are locked with Alice’s Public Key &amp; thus you would know the sum total of BTCs in Alice’s wallet (this is exactly the same way Alice’s wallet knows how much money she has - the coins aren’t actually in the wallet). Likewise, if you know Alice’s employer’s public key, you can figure out Alice’s salary. If you know anyone else’s Public Key, you can figure out if Alice has paid them or received money from them.</p>

<p>Monero fixes these issues &amp; makes transactions anonymous &amp; private.</p>

<h4 id="stealth-addresses">Stealth Addresses</h4>

<p>In Monero, each person (actually wallet) has 2 Elliptic Curve Key Pairs</p>

<ul>
  <li>View Public &amp; Private Key</li>
  <li>Spend Public &amp; Private Key</li>
</ul>

<p>Let Bob’s View Private Key be $v_b$ &amp; Spend Private Key be $s_b$ respectively. His View Public Key &amp; Spend Public key are $V_b = v_b G$ &amp; $S_b = s_b G$ respectively.</p>

<p>When Alice wants to send Money to Bob, Alice samples a random number $r$ &amp; computes $K_{dh}$</p>

<p>$K_{dh} = H_s(r V_b \space)$</p>

<p>If a transaction has multiple outputs, then index of the output is added to the Hash input to compute $K_{dh}$. I am ignoring it here (and other places also) to keep it simple.</p>

<p>Alice then computes a new derived one-time Output Public Key $P_o$ &amp; also computes $R$</p>

<p>$P_o = K_{dh}  G + S_b$</p>

<p>$R = r G$</p>

<p>Instead of sending money to Bob’s address as done in BTC, Alice sends the money to $P_o$ &amp; publishes $R$ in cleartext as part of the transaction data.</p>

<p>In the above expression $G$ and $S_b$ are publicly known. But $K_{dh} = H_s(r V_b \space)$ has a term $r$ which is known only to Alice.</p>

<p>However, $V_b = v_b G$ &amp; $R = r G$</p>

<p>$r V_b = r  (v_b G) = v_b  (r  G) = v_b R$</p>

<p>Since $v_b$ is known to Bob (and no one else), only Bob can compute $K_{dh} = H_s(v_b R)$ even without knowing $r$.</p>

<p>So above, Alice used Diffie-Hellman to share a secret $K_{dh}$ with Bob.</p>

<p>But most transactions have more than one output - either sender sends money to more than one receiver in the same transaction. If nothing else, she has to send change back to herself because the amount she wants to send to Bob will not match the exact amount of the input(s) she is spending. So, typically instead of just $K_{dh} = H_s(r V_b \space)$, we will have</p>

<p>$K^0_{dh} = H_s(r V^0_b \space)$</p>

<p>$K^1_{dh} = H_s(r V^1_b \space)$</p>

<p>where the superscript $0, 1, …$ etc is the output index - if a transaction has multiple ouputs, then it’s indexed as $0, 1, …$ etc</p>

<p>$V^i_b$ is the View Output Key of the receiver of the $i$-th receiver &amp; Alice will compute the corresponding one time Public Address as</p>

<p>$P^i_o = K^i_{dh}  G + S^i_b$</p>

<p>where $S^i_b$ is the $i$-th receiver’s spend Public Key</p>

<p>In BTC, everytime a new mined block appears, your wallet scans the block and finds transactions sent to your address. In Monero, your wallet uses the $R$ of each new transaction to compute $P_o$ from it (using Bob’s View Private Key) &amp; checks if the transaction is sent to $P_o$ to find transactions meant for him.</p>

<p>Only the View Private Key is required for viewing transactions coming to your wallet &amp; the Spend Private Key isn’t required.</p>

<p>The Output address $P_o =K_{dh}  G + S_b$</p>

<p>can be considered as</p>

<p>$P_o = K_{dh}  G + s_b  G$</p>

<p>$\quad = (K_{dh} + s_b) G$</p>

<p>Let $x_o = K_{dh} + s_b$</p>

<p>$P_o = x_o G$</p>

<p>So the private key for this output is considered as $x_o$.</p>

<p>When Bob wants to spend this output, he has to prove possession of $x_o$ - the view private key ($v_b$) &amp; the spend private key ($s_b$) both need to be known to know $x_o$ i.e. to spend the UXTO. So Bob can hand off his View Private to someone to delegate the responsibility of checking transactions without allowing them to spend it.</p>

<p>In BTC, where money is sent to non-secret addresses, in Monero, it’s sent to a one-time address to preserve privacy &amp; anonymity.</p>

<h4 id="amount-commitments">Amount Commitments</h4>

<p>In BTC, the amount is represented in the transaction entry as the actual value. In Monero, the transaction data has Pedersen commitments of the amounts instead. Since these commitments are Hiding, nobody else can figure out the amounts in any transaction.</p>

<p>The sender chooses the blinding factor $b$ for the commitments of the output as 
$b_v = H_s(“commitment\space mask”, K_{dh})$</p>

<p>The sender creates a Pedersen commitment for amount $v$ computed as</p>

<p>$C_v =  v G + b_v B$</p>

<p>There are already commitments for all inputs (created by whoever sent those amounts to sender). Sender creates commitments for all  outputs. She chooses blinding factors for different outputs except one randomly. And that one is chosen explicitly such that the sum of the input blinding factors is equal to the sum of the output blinding factors.</p>

<p>In BTC, the nodes verify that for every transaction, sum of inputs is greater than or equal to the sum of the outputs. Since Pedersen commitments are additively homomorphic, the nodes can verify if the sum of commitments of the inputs is greater than  or equal to the sum of the commitments of the output if the blinding factors are chosen as above.</p>

<p>The sender also encrypts the amount value ($v$) as below &amp; stores it in the transaction data</p>

<p>$EncAmt = v\space  \bigoplus_8 \space H_s(“amount”, K_{dh})$</p>

<p>Here $\bigoplus_8$ denotes XOR between the first 8 bytes of $v$ &amp; the Hash $H_s(…)$. Amounts on the blockchain are restricted to 8-byte values &amp; hence only 8 bytes are XORed.</p>

<p>Receiver also knows $K_{dh}$, so he can do a $\bigoplus_8$ of EncAmt with $H_s(“amount”, K_{dh})$ to get the Amount Value in cleartext. He also can compute the Blinding factor &amp; thus check the Pedersen Commitment to see if he received the amount he was expecting.</p>

<p>The strings passed as first param to the hash functions are for doing <a href="https://en.wikipedia.org/wiki/Domain_separation">Domain Separation</a></p>

<p>If there was no domain separation string used &amp; the computation was as below</p>

<p>$b_v = H_s(K_{dh})$</p>

<p>$Enc(val) = v\space  \bigoplus_8 \space H_s(K_{dh})$</p>

<p>This can lead to an attack to find out the actual amount being spent. If you combine both of the above, then you have</p>

<ul>
  <li>
    <p>$C_v = v G + b_v B$</p>
  </li>
  <li>
    <p>$b_v = H_s(K_{dh})$</p>
  </li>
  <li>
    <p>$Enc(v) = v\space  \bigoplus_8 \space b_v$</p>
  </li>
</ul>

<p>$Enc(v)$ &amp; $C_v$ are known - they are present in the transaction data. So if an attacker knows (or can guess) the general range of a transaction (that’s it’s between some amounts x to y XMR) - then they can try each of the values in the range to check if that fits in all 3 of the above equations. Domain Separation helps to prevent this.</p>

<p>Another thing here is that $K_{dh}$ is already a hash</p>

<p>$K_{dh} = H_s(r V_b \space)$</p>

<p>There is no security reason for hashing the hash $K_{dh}$ again. Earlier versions of Monero didn’t use domain separation &amp; instead used a single hash &amp; double hash in the 2 places so as to prevent the exhaustive search of a range to find out the cleartext amount. Once domain separation was implemented, I am guessing they had the choice to replace both places with either $K_{dh}$ or  $H_s(K_{dh})$. $H_s(K_{dh})$ is already computed in other places in the code, so it didn’t make a difference as to which of the two options they chose &amp; they chose the double hash.</p>

<h4 id="ringct">RingCT</h4>

<p>When spending a UTXO, if the sender signs it with the one time Private/Public Key pair, then even though others don’t know the Public Key, the person who sent the UTXO to the sender does know it (it was she who created the Diffie Hellman one time address). So she would know who is the spender in a new transaction spending the output she sent &amp; would know when it’s spent. To hide this, Monero uses Ring Confidential Transactions (RingCT). For ease of understanding, let’s take a transaction which has only 1 input. The spender collects multiple other TXOs from the Monero Blockchain to mix with her transaction - each TXO has a One-time Public Key &amp; Pedersen Commitments associated with it. The sender signs the Current Transaction with a Ring Signature using the Ring of Public Keys associated with the unrelated transactions to hide which UTXO is being spent. However, it’s not yet foolproof. The fact that the sender has set blinding factors such that the sum of the input commitments are equal to the sum of output commitments causes a privacy problem. Even though the sender signs the transaction using a Ring Signature to provide anonymity, only one of the those input commitments which would sum up to the output commitments of the current transaction - the output commitment of the current transactions won’t sum up to the input commitments of any of the dummy transactions in the Ring. This would make it easy to idenfity the sender’s UTXOs from the Ring of UTXOs. To avoid this issue, Monero adds another tweak.</p>

<p>The input UTXO amounts already have existing commitments created by the sender of those Transactions.</p>

<p>The existing input commitment of value $i$ is</p>

<p>$C_i = i G + b B $</p>

<p>The sender knows $b$ &amp; $i$ as described in the <a href="./#amount-commitments">Amount Commitments</a> section. The sender creates a new commitment for the same commitment with a different blinding factor</p>

<p>$C’_i = i G + b’B$</p>

<p>This is called as a Pseudo Commitment</p>

<p>Now $C_i - C’_i = (b - b’)B$ is a commitment to a $0$  amount because the $i G$ terms would cancel out. Only the sender knows the $z = b-b’$ which is the private key for the zero commitment. Let $P_z = z B$</p>

<p>We already have one Private Key ($x_o$) from the <a href="./#stealth-addresses">Stealth Addresses</a> section for which the Signer has to prove &amp; this is now a second one.</p>

<p>The spender chooses a blinding factor for both the Pseudo Commitments &amp; Output Commitments so that their blinding factors cancel each other out</p>

<p>Let a transaction be represented by 2 Inputs (A &amp; B) &amp; 2 Outputs (C &amp; D).</p>

<p>The check if $A + B \stackrel{?}{=} C + D$ can be done by checking if</p>

<p>$Pseudo_A + Pseudo_B \stackrel{?}{=} Out_C + Out_D$</p>

<p>where $Pseudo_A$ &amp; $Out_C$ are Pseudo Pedersen Commitment of Input A &amp; Pedersen Commitment of Output B respectively &amp; so on.</p>

<p><strong>Key Image</strong></p>

<p>Ring Signatures ensure that no one can figure out which is the TXO which is being spent. However, the downside of this is that the validators also can’t figure out the same &amp; hence they cannot validate if the TXO is being spent for the second time. The nodes can no longer maintain a list of UTXOs to prevent double spending. So Monero also embeds a Key Image in each transaction &amp; makes it part of the transaction data &amp; also the signature.</p>

<p>This is how a Key Image is computed</p>

<p>$KI = x_o\star H_p(P_o)$</p>

<p>where $P_o$ is the Public Key corresponding to the One-time Address &amp; $x_o$ is the correponding private key of $P_0$</p>

<p>If you notice, the Key Image is unique to a UTXO.  2 different transactions get linked if the same Key Pair is used to generate signature containing the same Key Image. This is called Linkability. Nodes maintain list of all Key Images which are already spent to prevent double spending. The Nodes verify if the Key Image of each transaction in a new block already exists in their list - if it does, that means that transaction is spending a TXO which has already been spent &amp; the nodes reject the block.</p>

<p>Also, the Key Image can be computed only by the person spending the UTXO &amp; not by the person who sent him the UTXO. So your employer who paid your salaries in Monero will not be able to find out which transaction you started spending it in.</p>

<p>A Ring Signature which allows validation of a Key Image is called as a Linkable Group Signature.</p>

<p><strong>MLSAG</strong></p>

<p>The signature has to prove possession of 2 private keys (the Private Key for the stealth address &amp; the one for the commitment to zero). Each unrelated TXO which Alice has rounded up to form the ring has a one-time Public Key of the receiver of that output ($P_o$). It also includes the Pseudo Pedersen Commitments of that transaction. The Pseudo Pedersen Commitment of that Transaction <em>minus</em> the original Input Pedersen commitment linked to that transaction gives us the second Public Key ($P_z$) - the signer knows these 2 Public Keys for each member of the Ring without knowing the corresponding Private Keys. She could  create a <a href="./#ring-signature-with-multiple-private-keys">Ring Signature with multiple private keys</a> by signing the transaction data. However, this signature doesn’t include the Key Image, so it’s tweaked further to create a Multilayer Linkable Spontaneous Anonymous Group Signatures (MLSAG).</p>

<p>Each Input TXO which is being spent in a transaction has a different stealth address even if belongs to the same spender. Each such address is a private key whose possession has to be proven by the spender. Other than that, the spender has to prove that he knows the private key to the zero commitment (Pseudo Commitment minus the Input Commitment).</p>

<p>In Monero, the Signer generates a signature for each UTXO she is spending in a transaction - i.e. if she spends money from 3 UTXOs in a transaction, she generates 3 MLSAG signatures for the transaction - each signatures is a proof of possession for the private key corresponding to the one time address of that UTXO &amp; also the private key for the commitment to zero generated from that UTXO.</p>

<p>For each input TXO, the spender collects other TXOs (not belonging to her) from the blockchain. Each such dummy TXO also has the Pseudo Commitments &amp; Output Commitments &amp; she can compute the Public Key corresponding to the zero commitment of that transaction (as can the validator) though she won’t know the private key to the zero commitment.</p>

<p>To the signature described in the <a href="./#ring-signature-with-multiple-private-keys">Ring Signature with multiple private keys</a> section, we add Key Image linking as described below.</p>

<p>This is how $c_{k+1}$ was computed</p>

<p>$c_{k+1} = H_s(M, R_{0,k},R_{1,k}, … , R_{m-1,k})$</p>

<p>We change this to</p>

<p>$KI = x_{m-1}\star hash_p(P_{m-1, k})$</p>

<p>$DKI_k = r_{m-1}\star hash_p(P_{m-1, k})$</p>

<p>$c_{k+1} = H_s(M, R_{0,k},R_{1,k}, … , R_{m-1,k}, DKI_k)$</p>

<p>Then for computing $c_{k+2}$,</p>

<p>$DKI_{k+1} = s_{m-1,k+1}\star hash_p(P_{m-1, k+1}) + c*KI$</p>

<p>$c_{k+2} = H_s(M, R_{0,k+1},R_{1,k+1}, … , R_{m-1,k+1}, DKI_{k+1})$</p>

<p>and so on</p>

<p>The signature resulting from this operation is $\lbrace KI, c_0,s_0,s_1,…,s_{n-1} \rbrace$</p>

<p><strong>Verification:</strong></p>

<ul>
  <li>Verifier computes $R_{i,0} = s_{i,0}G + c_{0}P_{i,0}$  for all $i \in \lbrace 0, …, m-1 \rbrace$</li>
  <li>Verifier computes $c_1 = H_s(M, R_{0,0},R_{1,0}, … , R_{m-1,0})$</li>
  <li>Verifier computes for $c_2, c_3$ similarly all the way till she computes</li>
</ul>

<p>$\qquad \qquad c_0 = H_s(M, R_{0,n-1},R_{1,n-1}, … , R_{m-1,n-1})$</p>

<p>If the computed $c_0$ equals the $c_0$ sent by the signer, then it means the signature has verified.</p>

<p>An additional check also needs done in Monero because unlike our example, Monero uses a Composite Order Curve. A signer could add a point on the Cofactor subgroup to the Key Image to get a new Key Image. And then create a signature with all $c_i$’s which are multiples of the order of the Cofactor Subgroup - this can be done by trial &amp; error. This will give the signer a 2nd Key Image &amp; Signature for the same UTXO which will verify correctly - thereby allowing double spending. Hence Monero validators check if the Key Image is a point on the main group of the elliptic curve, this is trivially checked by checking if $q KI \stackrel {?}{=}0$</p>

<p>A generalisation of MLSAG could compute a KeyImage for each one of the Private Keys in possession of the signer &amp; publish a Key Image Vector instead of just a Key Image. However, in the Monero usecase, it only makes sense to compute the KeyImage for the 1st key - i.e. the  spend key. Hence we do not do a Key Image for the commitment to zero.</p>

<p>Below is the sagemath program for a signature for spending one of the input UTXO of a transaction. Since each signature will always prove possession of 2 keys (One-time Address &amp; Commitment to Zero), we will always have $m=2$. Monero also fixes that the first row of the Matrix to be the One Time Address Public Key &amp; the 2nd row to be the Commitment to Zero Key - so the Key Image is generated from the First Row.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">pts_</span><span class="p">,</span> <span class="n">kpt_</span><span class="p">):</span>
    <span class="n">b</span> <span class="o">=</span> <span class="n">msg_</span>
    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
        <span class="n">b</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="n">point_to_bytes</span><span class="p">(</span><span class="n">pts_</span><span class="p">[</span><span class="n">j</span><span class="p">])</span> 
    <span class="n">b</span> <span class="o">=</span> <span class="n">b</span> <span class="o">+</span> <span class="n">point_to_bytes</span><span class="p">(</span><span class="n">kpt_</span><span class="p">)</span>
    <span class="n">h</span> <span class="o">=</span>  <span class="n">hashlib</span><span class="p">.</span><span class="nf">sha3_256</span><span class="p">(</span><span class="n">b</span><span class="p">).</span><span class="nf">digest</span><span class="p">()</span>
    <span class="k">return</span> <span class="no">Fq</span><span class="p">(</span><span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">))</span>

<span class="k">def</span> <span class="nf">hash_p</span><span class="p">(</span><span class="n">pt_</span><span class="p">):</span>
    <span class="n">h</span> <span class="o">=</span> <span class="n">hashlib</span><span class="p">.</span><span class="nf">sha3_256</span><span class="p">(</span><span class="n">point_to_bytes</span><span class="p">(</span><span class="n">pt_</span><span class="p">)).</span><span class="nf">digest</span><span class="p">()</span>
    <span class="k">return</span> <span class="n">int</span><span class="p">.</span><span class="nf">from_bytes</span><span class="p">(</span><span class="n">h</span><span class="p">,</span> <span class="n">byteorder</span><span class="o">=</span><span class="s2">"big"</span><span class="p">)</span><span class="o">*</span><span class="no">G</span>

<span class="k">def</span> <span class="nf">ring_multi_sign</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">Pubs_</span><span class="p">,</span> <span class="n">s_</span><span class="p">,</span> <span class="n">xs_</span><span class="p">):</span>
    <span class="n">sc</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="p">[:]</span> <span class="k">for</span> <span class="n">a</span> <span class="k">in</span> <span class="n">s_</span><span class="p">]</span> <span class="c1">## Deep Copy a 2d list</span>
    
    <span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">m</span>
    <span class="no">R</span> <span class="o">=</span> <span class="p">[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">m</span>

    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
        <span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>
        <span class="no">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">G</span>
    
    <span class="n">ki</span> <span class="o">=</span> <span class="n">xs_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">hash_p</span><span class="p">(</span><span class="no">Pubs_</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">k</span><span class="p">])</span>
    <span class="n">kpt</span> <span class="o">=</span> <span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">*</span><span class="n">hash_p</span><span class="p">(</span><span class="no">Pubs_</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">k</span><span class="p">])</span>
    
    <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">R</span><span class="p">,</span> <span class="n">kpt</span><span class="p">)</span>
    <span class="n">c0</span> <span class="o">=</span> <span class="n">c</span>

    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">):</span>
        <span class="n">idx</span> <span class="o">=</span> <span class="p">(</span><span class="n">j</span> <span class="o">+</span> <span class="n">k</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span><span class="o">%</span><span class="n">n</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
            <span class="no">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">sc</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">idx</span><span class="p">]</span><span class="o">*</span><span class="no">G</span> <span class="o">+</span> <span class="n">c</span><span class="o">*</span><span class="no">Pubs_</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">idx</span><span class="p">]</span>
            
        <span class="n">kpt</span> <span class="o">=</span> <span class="n">sc</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">idx</span><span class="p">]</span><span class="o">*</span><span class="n">hash_p</span><span class="p">(</span><span class="no">Pubs_</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">idx</span><span class="p">])</span> <span class="o">+</span> <span class="n">c</span><span class="o">*</span><span class="n">ki</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">R</span><span class="p">,</span> <span class="n">kpt</span><span class="p">)</span>
        <span class="k">if</span><span class="p">(</span><span class="n">idx</span> <span class="o">==</span> <span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">1</span><span class="p">)):</span>
            <span class="n">c0</span> <span class="o">=</span> <span class="n">c</span>

        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>   
            <span class="n">sc</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">r</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">c</span><span class="o">*</span><span class="n">xs_</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

    <span class="k">return</span> <span class="p">(</span><span class="n">c0</span><span class="p">,</span> <span class="n">sc</span><span class="p">,</span> <span class="n">ki</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">multi_ring_verify</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="n">sig_</span><span class="p">,</span> <span class="no">Pubs_</span><span class="p">):</span>
    <span class="n">c</span> <span class="o">=</span> <span class="n">sig_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">sig_</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
    <span class="n">ki</span> <span class="o">=</span> <span class="n">sig_</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="no">R</span> <span class="o">=</span> <span class="p">[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">m</span>
        <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
            <span class="no">R</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">*</span><span class="no">G</span> <span class="o">+</span> <span class="n">c</span><span class="o">*</span><span class="no">Pubs_</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span>
        <span class="n">kpt</span> <span class="o">=</span> <span class="n">s</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">j</span><span class="p">]</span><span class="o">*</span><span class="n">hash_p</span><span class="p">(</span><span class="no">Pubs_</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">j</span><span class="p">])</span> <span class="o">+</span> <span class="n">c</span><span class="o">*</span><span class="n">ki</span>
        <span class="n">c</span> <span class="o">=</span> <span class="n">hash_s</span><span class="p">(</span><span class="n">msg_</span><span class="p">,</span> <span class="no">R</span><span class="p">,</span> <span class="n">kpt</span><span class="p">)</span>

    <span class="k">return</span> <span class="p">(</span><span class="n">sig_</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="n">c</span><span class="p">)</span>

<span class="c1">#Main</span>
<span class="n">m</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># No of private keys known by signer (Rows)</span>
<span class="n">n</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># Total number of Public Keys in each Ring (Columns)</span>
<span class="n">k</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1"># The index Column index of the Signer's Keys</span>

<span class="no">Pubs</span> <span class="o">=</span> <span class="p">[[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">n</span> <span class="k">for</span> <span class="n">_</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">)]</span>
<span class="n">s</span> <span class="o">=</span> <span class="p">[[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">n</span> <span class="k">for</span> <span class="n">_</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">)]</span>

<span class="no">Ps</span> <span class="o">=</span> <span class="p">[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">m</span> <span class="c1"># Signer's Public Keys</span>
<span class="n">xs</span> <span class="o">=</span> <span class="p">[</span><span class="no">None</span><span class="p">]</span><span class="o">*</span><span class="n">m</span> <span class="c1"># Signer's Private Keys</span>

<span class="c1"># Generate the main Public/Private Key Pair for the signer</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
    <span class="n">xs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>
    <span class="no">Ps</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">xs</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">G</span>

<span class="c1"># We generate n*m random Public Keys. We also sample n*m s's</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="p">):</span>
        <span class="no">Pubs</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span><span class="o">*</span><span class="no">G</span>
        <span class="n">s</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">.</span><span class="nf">random_element</span><span class="p">()</span>

<span class="c1"># Overwrite the k'th element with the Signer's Public Key</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">):</span>
    <span class="no">Pubs</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="no">Ps</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

<span class="n">msg</span> <span class="o">=</span> <span class="s1">'HelloWorld'</span><span class="p">.</span><span class="nf">encode</span><span class="p">(</span><span class="s1">'utf8'</span><span class="p">)</span>

<span class="n">sig</span> <span class="o">=</span> <span class="n">ring_multi_sign</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="no">Pubs</span><span class="p">,</span> <span class="n">s</span><span class="p">,</span> <span class="n">xs</span><span class="p">)</span>
<span class="k">if</span><span class="p">(</span><span class="n">multi_ring_verify</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">sig</span><span class="p">,</span> <span class="no">Pubs</span><span class="p">)</span> <span class="o">==</span> <span class="no">True</span><span class="p">):</span>
    <span class="nb">print</span><span class="p">(</span><span class="s2">"Signature Verified"</span><span class="p">)</span>
</code></pre></div></div>

<p>One more validation needs to be done - a check that each of the outputs lies in the range between $0$ and $2^{64} - 1$. I have covered that in a Separate Post - <a href="/Bulletproofs/">Bulletproofs &amp; Range Proofs in Monero using Bulletproofs</a></p>
<h3 id="monero-transaction-structure-and-data">Monero Transaction Structure and Data</h3>

<p>Below is the JSON structure of a Monero Spend Transaction data - the JSON field name in bold &amp; what it represents in brackets. I have skipped some fields which aren’t significant</p>

<ul>
  <li><strong>Tx hash</strong> (Transaction Id)
    <ul>
      <li><strong>version</strong> (Version - version 2 means RingCT signatures)</li>
    </ul>
  </li>
  <li><strong>vin</strong> (below fields for each Input/UTXO being spent)
    <ul>
      <li><strong>key_offsets</strong> (a link to each input transaction on the blockchain including the dummy transactions used in the signature)</li>
      <li><strong>k_image</strong> (the Key Image generated for that Input)</li>
    </ul>
  </li>
  <li><strong>vout</strong> (below fields for each output of the transaction)
    <ul>
      <li><strong>target:[key]</strong> (one-time stealth address of the recipient)</li>
      <li><strong>extra</strong> (the $R$ corresponding to the stealth address)</li>
    </ul>
  </li>
  <li><strong>rct_signatures</strong> (though the name is rct_signatures, this field doesn’t contain the signature which is actually stored in the field MGs)
    <ul>
      <li><strong>txnfee</strong> (Transaction Fee)</li>
      <li><strong>pseudoOuts</strong> (list of all psuedo commitments for the transaction - one for each vin)</li>
      <li><strong>ecdhInfo</strong> (contains below list of items - one item for each vout)
        <ul>
          <li><strong>mask</strong> (blinding factor for the commitment)</li>
          <li><strong>amount</strong> (EncAmt)</li>
        </ul>
      </li>
      <li><strong>outPk</strong> (list of output Pedersen commitments)</li>
    </ul>
  </li>
  <li><strong>rangeSigs</strong> (Range Proofs)</li>
  <li><strong>MGs</strong> (list of signatures, one for each vin. Each signature containing the following fields)
    <ul>
      <li><strong>ss</strong> (the list - $\lbrace s_0,s_1,…,s_{n-1} \rbrace$</li>
      <li><strong>cc</strong> ($c_0$ of the signature)</li>
    </ul>
  </li>
</ul>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FMonero%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Groth16 zkSNARK</title><link href="https://risencrypto.github.io/Groth16/" rel="alternate" type="text/html" title="Groth16 zkSNARK" /><published>2024-07-24T00:00:00+00:00</published><updated>2024-07-24T00:00:00+00:00</updated><id>https://risencrypto.github.io/Groth16</id><content type="html" xml:base="https://risencrypto.github.io/Groth16/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<p>Groth16 is a zkSNARK protocol introduced by Jens Groth in 2016 &amp; it saw an early application in ZCash. Its proof size is among the smallest (consisting of only three elliptic curve elements) and it is also the fastest to verify</p>

<h3 id="pre-requisite-topics">Pre-requisite Topics</h3>

<p><strong>The Schwartz-Zippel Lemma</strong></p>

<p>Let $f$ be a polynomial from $\mathbb F_p[x]$ of degree less than or equal to $d$. Let $p \approx 2^{256}$ &amp; $d \le 2^{40}$. If we test $f$ at a random value $r \in \mathbb F_p$, then the probability that $f(r) = 0$ would be $\frac {d}{p}$ which for these values of $d$ &amp; $p$ would be very, very small. So, if $f(r) = 0$, then with high probability, $f$ is a zero polynomial (i.e., zero at all points).</p>

<p>This also helps to prove that 2 polynomials are equal. If the 2 polynomials are $f$ &amp; $g$, we create a new polynomial $p(x) = f(x)\space - \space g(x)$.</p>

<p>If we test $p$ at a random $r \in \mathbb F_p$ &amp; $f(r)$ turns out to be $0$, then $p$ is a zero polynomial with very high probability. If $p$ is a zero polynomial, then it obviously means $f = g$</p>

<p><strong>Polynomial Commitment Schemes &amp; Elliptic Curve Pairings</strong></p>

<p>Though Groth16 doesn’t exactly use KZG Commitments, it uses something very similar. If you are not familiar with this type of Polynomial Commitment Schemes, you can go through this post on <a href="/Kate/">KZG Polynomial Commitment Scheme</a>. It will introduce you to both Polynomial Commitment Schemes &amp; Elliptic Curve Pairings.</p>

<p>We will use an Asymmetric Elliptic Curve Pairing setup</p>

<p>$e : \mathbb G_1 \times \mathbb G_2 \mapsto \mathbb G_T$</p>

<p>$G_1$ &amp; $G_2$ are generators of cyclic groups $\mathbb G_1$ &amp; $\mathbb G_2$ respectively.</p>

<p>The core properties of Elliptic Curve Pairings which we use here are the following where $a$ &amp; $b$ are scalars</p>

<ul>
  <li>$e(a G_1, b G_2) = e(b G_1, a G_2) = e(ab G_1, G_2) = e(G_1, ab G_2) = e(G_1, a G_2)^{b} = e(G_1, G_2)^{ab}$</li>
</ul>

<p>If $m = a\cdot b + c \cdot d$, then</p>

<p>$e(mG_1,G_2)=e((ab+cd)G_1, G_2)$</p>

<p>$\qquad\qquad = e(G_1,G_2)^{ab+cd}$</p>

<p>$\qquad\qquad = e(G_1,G_2)^{ab}\cdot e(G_1,G_2)^{cd}$</p>

<p>$\qquad\qquad = e(aG_1, bG_2)\cdot e(cG_1,dG_2)$</p>

<p>So, if we want to prove $m = a\cdot b + c \cdot d$, we can do so by proving</p>

<p>$e(mG_1,G_2) = e(G_1,G_2)^{ab}\cdot e(G_1,G_2)^{cd}$</p>

<h3 id="the-basic-idea">The Basic Idea</h3>

<p>The Prover wants to prove to the Verifier that she knows the solution to a particular equation without revealing the solution itself. In order for her to do this, the equation has to be first converted to the Rank-1 Constraint System (R1CS)  &amp; then to the Quadratic Arithmetic Program (QAP) form. I have covered the conversion here - <a href="/R1CSQAP/">R1CS and QAP - From Zero to Hero</a>.</p>

<p>The current post covers what happens after the conversion.</p>

<p>We have polynomials $L, R, O, H$ known only to the Prover &amp; $Z$ known to both the Prover &amp; Verifier - all these are in the Polynomial Ring $\mathbb F_{641}[x]$</p>

<p>$L(x) = 529x^3 + 359x^2 + 354x + 43$</p>

<p>$R(x) = 428x^3 + 636x^2 + 224x + 638$</p>

<p>$O(x) = 537x^3 + 296x^2 + 499x + 600$</p>

<p>$H(x) = 139x^2 + 480x + 210$</p>

<p>$Z(x) = (x−1)(x−2)(x−3)(x−4)$</p>

<p>Let $Q = O + H\cdot Z$</p>

<p>The Prover has to prove $L\cdot R = Q$</p>

<p>For a polynomial $F(x)$, we will denote its commitment in the Group $\mathbb G_n$ as $[F]_n$. (In sagemath code, we will denote it as CFn)</p>

<p>Prover computes commitments $[L]_1, [R]_2$ &amp; $[Q]_1$ &amp; sends it to Verifier.</p>

<p>Verifier can then verify if $L\cdot R \stackrel {?}{=} Q$ by checking if the following equality holds</p>

<p>$e([L]_1,[R]_2) \stackrel {?}{=} e([Q]_1, G2)$</p>

<p><strong>Powers of Tau</strong></p>

<p>We create the toy curve &amp; the generators we use for our example in Sage</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">q</span> <span class="o">=</span> <span class="mi">7691</span>
<span class="no">Fq</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="n">q</span><span class="p">)</span>
<span class="no">Eq</span> <span class="o">=</span> <span class="no">EllipticCurve</span><span class="p">(</span><span class="no">Fq</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span>
<span class="no">Fqr</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">r</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">Fq</span><span class="p">[]</span>
<span class="no">Fq_2</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">v</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="n">q</span><span class="o">^</span><span class="mi">2</span><span class="p">,</span> <span class="nb">name</span> <span class="o">=</span> <span class="s1">'v'</span><span class="p">,</span> <span class="n">modulus</span> <span class="o">=</span> <span class="no">Fqr</span><span class="p">(</span><span class="n">r</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">1</span><span class="p">))</span>
<span class="no">ExtEq</span> <span class="o">=</span> <span class="no">EllipticCurve</span><span class="p">(</span><span class="no">Fq_2</span><span class="p">,</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">])</span>
<span class="no">G1</span> <span class="o">=</span> <span class="no">ExtEq</span><span class="p">([</span><span class="mi">2693</span><span class="p">,</span> <span class="mi">4312</span><span class="p">])</span>
<span class="no">G2</span> <span class="o">=</span> <span class="no">ExtEq</span><span class="p">(</span><span class="mi">633</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">6145</span><span class="p">,</span> <span class="mi">7372</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">109</span><span class="p">)</span>
<span class="no">G1</span><span class="p">.</span><span class="nf">order</span><span class="p">()</span>
<span class="mi">641</span>
<span class="no">G2</span><span class="p">.</span><span class="nf">order</span><span class="p">()</span>
<span class="mi">641</span>

<span class="nb">p</span> <span class="o">=</span> <span class="mi">641</span>
<span class="no">Fp</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="nb">p</span><span class="p">)</span>
<span class="no">Rng</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">Fp</span><span class="p">)</span>
</code></pre></div></div>

<p>For commitments, we need a trusted setup. A random value $\tau \in \mathbb F_{641}$ is sampled - $\tau = 266$. This is like the $a$ in the <a href="/Kate/#trusted-setup">KZG Trusted Setup</a>.</p>

<p>Our CRS will look like $CRS_i = \lbrace \tau^0 G_i, \tau^1 G_i, \tau^2 G_i, … \rbrace$. We need to have as many powers as the degree of the highest polynomial we want to commit. The term $H\cdot Z$ (part of the polynomial $C$) has a degree $2n-2$ &amp; for $G_1$, we would need powers up to $\tau^{2n-2} G_1$. For $G_2$, we only need up to $\tau^{n-1}\cdot G_2$ because we commit only $R$ which is of degree $n-1$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Randomly Sampled tau</span>
<span class="n">t</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">266</span><span class="p">)</span>

<span class="no">CRS1</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span><span class="o">^</span><span class="mi">0</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">1</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">2</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">3</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">4</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">5</span> <span class="o">*</span> <span class="no">G1</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">6</span> <span class="o">*</span> <span class="no">G1</span><span class="p">]</span>

<span class="no">CRS2</span> <span class="o">=</span> <span class="p">[</span><span class="n">t</span><span class="o">^</span><span class="mi">0</span> <span class="o">*</span> <span class="no">G2</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">1</span> <span class="o">*</span> <span class="no">G2</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">2</span> <span class="o">*</span> <span class="no">G2</span><span class="p">,</span> <span class="n">t</span><span class="o">^</span><span class="mi">3</span> <span class="o">*</span> <span class="no">G2</span><span class="p">]</span>
</code></pre></div></div>

<p>$H\cdot Z = 139x^6 + 372x^5 + 275x^4 + 58x^3 + 147x^2 + 379x + 553$</p>

<p>In sagemath, we calculate commitments $[L]_1, [R]_2, [O]_1, [HZ]_1 $. These commitments are additively homomorphic &amp; so $[Q]_1 = [O]_1 + [HZ]_1$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CL1</span> <span class="o">=</span> <span class="mi">529</span> <span class="o">*</span> <span class="no">CRS1</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">+</span> <span class="mi">359</span> <span class="o">*</span> <span class="no">CRS1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">+</span> <span class="mi">354</span> <span class="o">*</span> <span class="no">CRS1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="mi">43</span> <span class="o">*</span> <span class="no">CRS1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

<span class="p">(</span><span class="mi">626</span> <span class="p">:</span> <span class="mi">4218</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)</span>

<span class="c1">### Likewise compute commitments CR2 &amp; CQ1</span>

<span class="c1">### Display the 3 commitments </span>

<span class="no">CL1</span><span class="p">,</span> <span class="no">CR2</span><span class="p">,</span> <span class="no">CQ1</span>
<span class="p">((</span><span class="mi">626</span> <span class="p">:</span> <span class="mi">4218</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">2557</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">3335</span> <span class="p">:</span> <span class="mi">6647</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">6264</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">1297</span> <span class="p">:</span> <span class="mi">4026</span> <span class="p">:</span> <span class="mi">1</span><span class="p">))</span>
</code></pre></div></div>
<p>Prover sends these commitments to the Verifier</p>

<p>Verifier checks if $e([L]_1,[R]_2) \stackrel {?}{=} e([D]_1, G2)$ using Pairings in sagemath.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## Left Hand Side</span>
<span class="no">CL1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">CR2</span><span class="p">,</span> <span class="nb">p</span><span class="p">)</span>
<span class="mi">7480</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2304</span>

<span class="c1">## Right Hand Side</span>
<span class="no">CQ1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">G2</span><span class="p">,</span><span class="nb">p</span><span class="p">)</span>
<span class="mi">7480</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2304</span>
</code></pre></div></div>

<p>As you can see, the check verifies. This can be followed by opening the commitments at a random point.</p>

<h3 id="problems">Problems</h3>

<p>$1)$ The above proof is Complete, but it’s not Sound. A dishonest Prover can easily generate fake commitments which satisfy the above test.</p>

<p>Prover generates two random numbers $k_1$ &amp; $k_2$ &amp; generates fake commitments which pass the pairing test</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">k1</span> <span class="o">=</span> <span class="mi">23</span>
<span class="n">k2</span> <span class="o">=</span> <span class="mi">41</span>
<span class="no">L1</span> <span class="o">=</span> <span class="n">k1</span><span class="o">*</span><span class="no">G1</span>
<span class="no">R2</span> <span class="o">=</span> <span class="n">k2</span><span class="o">*</span><span class="no">G2</span>
<span class="no">C1</span> <span class="o">=</span> <span class="n">k1</span> <span class="o">*</span> <span class="n">k2</span> <span class="o">*</span> <span class="n">g1</span>

<span class="no">L1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">R1</span><span class="p">,</span><span class="nb">p</span><span class="p">)</span>
<span class="mi">1732</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">3636</span>
<span class="no">C1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">G2</span><span class="p">,</span> <span class="nb">p</span><span class="p">)</span>
<span class="mi">1732</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">3636</span>
</code></pre></div></div>

<p>This works because of one of the properties of pairings which we listed earlier</p>

<p>$e(a G_1, b G_2)  = e(ab G_1, G_2)$</p>

<p>$2)$ We created the $L, R$ &amp; $O$ polynomials by multiplying the QAP matrix with the Solution Vector $S$</p>

<p>$S = [1, out, x, var1, var2, var3]$</p>

<p>The values of first 2 elements of the Solution vector are known to both Prover &amp; Verifier - i.e. they are public inputs - the set of these elements is called <strong>Instance</strong>. The other 4 elements are known only to Prover &amp; not to the verifier - they are private inputs - called <strong>Witness</strong>.</p>

<p>Even assuming that the Prover didn’t generate the proof using random values, the Verifier cannot verify that these were generated using the Public Inputs/Instance which is known to him. How does the Verifier know that the value of $out$ used was $35$?</p>

<p>$3)$ The $QAP$ &amp; the Instance is known to both the prover &amp; the verifier. The proof is a composition of them along with the witness. Just like the verifier cannot know if the Prover used the Instance, he also cannot know if the Prover used the known $QAP$.</p>

<p>We will modify the proof to fix the above &amp; more problems.</p>

<h3 id="separating-public--private-inputs">Separating Public &amp; Private Inputs</h3>
<p>We created each of the polynomials by multiplying the corresponding Matrix by the solution vector - for e.g. $L(x)$ was created by multiplying the Solution Vector by $L_m$ (or $PolyM[0]$). We then  constructed the equation $L\cdot R  = O + H\cdot Z$ which we proved.</p>

<p>We will do it a little different now.</p>

<p>Our $L_m$ or $PolyM[0]$ from the QAP</p>

\[L_m = PolyM[0] = \begin{pmatrix}
636&amp;116&amp;636&amp;535 \\
0&amp;0&amp;0&amp;0 \\
8&amp;416&amp;5&amp;213 \\
635&amp;330&amp;637&amp;321 \\
4&amp;634&amp;324&amp;320 \\
640&amp;536&amp;640&amp;107
\end{pmatrix}\]

<p>We consider each row as a Polynomial - i.e. the first row here represents the Polynomial $535x^3 + 636x^2 + 116x + 636$</p>

<p>We can form the polynomials from Matrix $L_m$ this way</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Pl</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="no">PolyM</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nf">nrows</span><span class="p">()):</span>
     <span class="no">Pl</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Rng</span><span class="p">(</span><span class="n">list</span><span class="p">(</span><span class="no">PolyM</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i</span><span class="p">])))</span>
</code></pre></div></div>

<p>If we print out $P_l$ array, we get</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="mi">535</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">636</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">116</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">636</span><span class="p">,</span>
 <span class="mi">0</span><span class="p">,</span>
 <span class="mi">213</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">5</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">416</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">8</span><span class="p">,</span>
 <span class="mi">321</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">637</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">330</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">635</span><span class="p">,</span>
 <span class="mi">320</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">324</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">634</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">4</span><span class="p">,</span>
 <span class="mi">107</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">640</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">536</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">640</span><span class="p">]</span>
</code></pre></div></div>

<p>We can multiply each of the 6 polynomials in the $P_l$ array &amp; multiply it with the corresponding element in the solution vector &amp; add all the 6 outputs together we get the following</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">ls</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">len</span><span class="p">(</span><span class="no">Pl</span><span class="p">)):</span>
     <span class="n">ls</span> <span class="o">=</span> <span class="n">ls</span> <span class="o">+</span> <span class="no">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="no">Pl</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">ls</span><span class="p">)</span>
<span class="mi">529</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">359</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">354</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">43</span>
</code></pre></div></div>
<p>If you check $ls$, it’s the same as our original $L(x)$</p>

<p>For ease of reading, let’s indicate the array elements of the solution vector as $S_i$ instead of $S[i]$ &amp; the Left Polynomials as $L_i$ instead $P_r[i]$</p>

<p>So $L(x)$ can be expressed as</p>

<p>So $L = \sum\limits_{i = 0}^{m-1}S_iL_i$</p>

<p>where $m=6$ is the number of elements in the Solution Vector.</p>

<p>Expressing $L$ this way means, we can process the public &amp; private parts of the Solution vector separately.</p>

<p>$l=2$ is number of public elements.</p>

<p>$L = \sum\limits_{i = 0}^{l-1}S_iL_i + \sum\limits_{i = l}^{m-1}S_iL_i$</p>

<p>Let,</p>

<p>$L_v = \sum\limits_{i = 0}^{l-1}S_iL_i$</p>

<p>$L_p = \sum\limits_{i = l}^{m-1}S_iL_i$</p>

<p>The subscript $p$ in $L_p$ is to denote that this part of each polynomial is known only to Prover, while subscript $v$ is to denote its Public Input &amp; known to the Verifier also.</p>

<h3 id="fixing-problems">Fixing Problems</h3>

<p>During the Trusted Setup, 4 random elements are sampled - $\alpha, \beta, \gamma, \delta$. None of these are known to Prover or Verifier. These along with $\tau$ are known as the Simulation Trapdoor.</p>

<p>And when the prover generates the proof, she samples 2 more random elements $r_1$ &amp; $r_2$ for randomising the proof.</p>

<p>We create new Polynomials</p>

<p>$A = L + \alpha + r_1\delta$</p>

<p>$B = R + \beta + r_2\delta$</p>

<p>Multiplying,</p>

<p>$AB = \alpha\beta + \alpha R + \alpha r_2\delta + \beta L + LR + r_2\delta L +r_1\beta\delta  + r_1\delta R + r_1r_2\delta^2$</p>

<p>Substituting in the above the following</p>

<p>$\qquad LR = O + HZ$</p>

<p>$\qquad L = L_v + L_p$</p>

<p>$\qquad R = R_v + R_p$</p>

<p>$\qquad O = O_v + O_p$</p>

<p>$AB = \alpha\beta + \alpha(R_v + R_v) + r2\alpha\delta + \beta(L_p + L_v) + (O_v + O_p) + HZ + r_2\delta L +r_1\beta\delta  + r_1\delta R + r_1r_2\delta^2$</p>

<p>Rearranging,</p>

<p>$AB = \alpha\beta + (\beta Lv + \alpha Rv + O_v) + (\beta Lp + \alpha Rp + O_p + HZ) + r_2\alpha\delta +  r_2\delta L +r_1\beta\delta  + r_1\delta R + r_1r_2\delta^2$</p>

<p>Let $I = \frac {\beta Lv + \alpha Rv + O_v}{\gamma}$ and</p>

<p>Let $J = \frac{\beta Lp + \alpha Rp + O_p + HZ}{\delta}$</p>

<p>$AB = \alpha\beta + I\cdot \gamma + (J +  r_2\alpha +  r_2 L +r_1\beta + r_1 R + r_1r_2\delta)\cdot\delta$</p>

<p>$AB = \alpha\beta + I\cdot \gamma + (J +  r_2(L + \alpha) +r_1(R +\beta) +  r_1r_2\delta)\cdot\delta$</p>

<p>Substituting in the above,</p>

<p>$\qquad L + \alpha = A - r_1\delta$</p>

<p>$\qquad R + \beta = B - r_2\delta$</p>

<p>$AB = \alpha\beta + I\cdot \gamma + (J +  r_2(A - r_1\delta) +r_1(B -r_2\delta) +  r_1r_2\delta)\cdot\delta$</p>

<p>$AB = \alpha\beta + I\cdot \gamma + (J +  r_2A - r_1r_2\delta +r_1 B -r_1r_2\delta +  r_1r_2\delta)\cdot\delta$</p>

<p>$AB = \alpha\beta + I\cdot \gamma + (J +  r_2A +r_1 B -r_1r_2\delta)\cdot\delta$</p>

<p>Let $C = J +  r_2A +r_1 B -r_1r_2\delta$</p>

<p>So, our final equation to prove is</p>

\[\\

AB = \alpha\beta + I\cdot \gamma + C\cdot\delta

\\\]

<p>where,</p>

<p>$I = \frac {\beta Lv + \alpha Rv + O_v}{\gamma}$ and</p>

<p>$C = \frac{\beta Lp + \alpha Rp + O_p + HZ}{\delta} +  r_2A +r_1 B -r_1r_2\delta$</p>

<p>Prover computes 3 commitments $[A]_1, [B]_1, [C]_1$ &amp; sends them to the verifier.</p>

<p>Verifier computes the commitments $[I]_1,[\alpha]_1, [\beta]_2, [\gamma]_2, [\delta]_2$</p>

<p>Using the $m = ab + cd$ property of pairings we introduced in the pre-requisites section, verifier can verify if</p>

<p>$A B \stackrel {?}{=} \alpha\beta + I \gamma + C\delta$</p>

<p>by checking if</p>

<p>$e([A]_1, [B]_2) \stackrel {?}{=} e([\alpha]_1, [\beta]_2) \cdot e(I, [\gamma]_2) \cdot e([C]_1, [\delta]_2)$</p>

<p>Later in the post, we discuss how these changes fix the problems.</p>

<h3 id="trusted-setup">Trusted Setup</h3>

<p>To accommodate all the above changes, we have to add more elements to the trusted setup.</p>

<p><strong>Phase 1:</strong></p>

<p>We already saw the powers of $\tau$ in $CRS_1$ &amp; $CRS_2$ right at the beginning.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CRS1</span>
<span class="p">[(</span><span class="mi">2693</span> <span class="p">:</span> <span class="mi">4312</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">5445</span> <span class="p">:</span> <span class="mi">1084</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">4704</span> <span class="p">:</span> <span class="mi">5111</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">2636</span> <span class="p">:</span> <span class="mi">806</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">760</span> <span class="p">:</span> <span class="mi">3470</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">7111</span> <span class="p">:</span> <span class="mi">4864</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">7124</span> <span class="p">:</span> <span class="mi">4829</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>

<span class="no">CRS2</span>
<span class="p">[(</span><span class="mi">633</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">6145</span> <span class="p">:</span> <span class="mi">7372</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">109</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">6256</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1837</span> <span class="p">:</span> <span class="mi">4186</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2463</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">6858</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">4226</span> <span class="p">:</span> <span class="mi">2462</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">4671</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">5012</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2956</span> <span class="p">:</span> <span class="mi">1090</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2261</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>
</code></pre></div></div>

<p>Groth16 Trusted Setup has 2 phases - the above is Phase 1 or Universal Setup. If you create a Phase 1 setup for a circuit of $n$ gates, it can be reused for any Circuit which has $n$ or less gates. $\tau$ is destroyed after Phase 1 is over.</p>

<p><strong>Phase 2:</strong></p>

<p>The 2nd Phase is circuit specific since it uses the $QAP$ of the circuit.</p>

<p>$-$ Trapdoor elements</p>

<p>The setup samples 4 Random elements $\in \mathbb F_{641}$ and computes their commitments</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## Random </span>
<span class="n">a</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">177</span><span class="p">)</span> <span class="c1"># alpha</span>
<span class="n">b</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">274</span><span class="p">)</span> <span class="c1"># beta</span>
<span class="n">g</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">502</span><span class="p">)</span> <span class="c1"># gamma</span>
<span class="n">d</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">138</span><span class="p">)</span> <span class="c1"># delta</span>

<span class="no">CRSTrap1</span> <span class="o">=</span> <span class="p">[</span><span class="n">a</span><span class="o">*</span><span class="no">G1</span><span class="p">,</span> <span class="n">b</span><span class="o">*</span><span class="no">G1</span><span class="p">,</span> <span class="n">d</span><span class="o">*</span><span class="no">G1</span><span class="p">]</span>
<span class="no">CRSTrap2</span> <span class="o">=</span> <span class="p">[</span><span class="n">b</span><span class="o">*</span><span class="no">G2</span><span class="p">,</span> <span class="n">g</span><span class="o">*</span><span class="no">G2</span><span class="p">,</span> <span class="n">d</span><span class="o">*</span><span class="no">G2</span><span class="p">]</span>

<span class="no">CRSTrap1</span>
<span class="p">[(</span><span class="mi">7111</span> <span class="p">:</span> <span class="mi">2827</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">836</span> <span class="p">:</span> <span class="mi">3029</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">1941</span> <span class="p">:</span> <span class="mi">3313</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>

<span class="no">CRSTrap2</span>
<span class="p">[(</span><span class="mi">7669</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1046</span> <span class="p">:</span> <span class="mi">7678</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">6427</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">4004</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">353</span> <span class="p">:</span> <span class="mi">7567</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">6151</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span>
 <span class="p">(</span><span class="mi">488</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">5968</span> <span class="p">:</span> <span class="mi">7624</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">4698</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>
</code></pre></div></div>

<p>$-$ CRS of Public &amp; Private Part of the Polynomials</p>

<p>$CRSpub = [{\lbrace}\frac{\beta L_i + \alpha R_i + O_i}{\gamma}\cdot G_1\rbrace_{i=0}^{l-1}]$</p>

<p>$CRSprv = [\lbrace\frac{\beta L_i + \alpha R_i + O_i}{\gamma}\cdot G_1\rbrace_{i=l}^{m-1}]$</p>

<p>We compute these using the $P_l, P_r, P_o$ we computed earlier.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">commit</span><span class="p">(</span><span class="no">F</span><span class="p">,</span> <span class="no">CRS</span><span class="p">):</span>
    <span class="n">cof</span> <span class="o">=</span> <span class="no">F</span><span class="p">.</span><span class="nf">list</span><span class="p">()</span>
    <span class="n">d</span> <span class="o">=</span> <span class="no">F</span><span class="p">.</span><span class="nf">degree</span><span class="p">()</span>
    <span class="n">com</span> <span class="o">=</span> <span class="no">ExtEq</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">d</span><span class="o">+</span><span class="mi">1</span><span class="p">):</span>
        <span class="n">com</span> <span class="o">=</span> <span class="n">com</span> <span class="o">+</span> <span class="n">cof</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">CRS</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>
    <span class="k">return</span> <span class="n">com</span>

<span class="no">CRSPub</span> <span class="o">=</span> <span class="p">[]</span>
<span class="no">CRSPrv</span> <span class="o">=</span> <span class="p">[]</span>

<span class="c1"># We use Pl, Pr, Po computed earlier from the QAP</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">l</span><span class="p">):</span>
    <span class="no">CRSPub</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">commit</span><span class="p">(</span><span class="no">Rng</span><span class="p">((</span><span class="n">b</span> <span class="o">*</span> <span class="no">Pl</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">a</span><span class="o">*</span><span class="no">Pr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="no">Po</span><span class="p">[</span><span class="n">i</span><span class="p">])</span><span class="o">/</span><span class="n">g</span><span class="p">),</span><span class="mi">1</span><span class="p">))</span>
    
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">l</span><span class="p">,</span><span class="n">m</span><span class="p">)):</span>
    <span class="no">CRSprv</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">commit</span><span class="p">(</span><span class="no">Rng</span><span class="p">((</span><span class="n">b</span> <span class="o">*</span> <span class="no">Pl</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">a</span><span class="o">*</span><span class="no">Pr</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="no">Po</span><span class="p">[</span><span class="n">i</span><span class="p">])</span><span class="o">/</span><span class="n">d</span><span class="p">),</span> <span class="no">CRS1</span><span class="p">))</span>

<span class="no">CRSPub</span>
<span class="p">[(</span><span class="mi">516</span> <span class="p">:</span> <span class="mi">6246</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">5397</span> <span class="p">:</span> <span class="mi">7026</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>

<span class="no">CRSPrv</span>
<span class="p">[(</span><span class="mi">1604</span> <span class="p">:</span> <span class="mi">6439</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">2473</span> <span class="p">:</span> <span class="mi">5808</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">1576</span> <span class="p">:</span> <span class="mi">4715</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">5416</span> <span class="p">:</span> <span class="mi">1062</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>
</code></pre></div></div>

<p>$-$ CRS for computing $HZ$</p>

<p>$CRShz = [\lbrace\frac {\tau^i Z(\tau)}{\delta} G_1\rbrace_{i=0}^{n-2} ]$</p>

<p>We don’t know $\tau$ or $Z(\tau)$, so how do we compute this list?</p>

<p>Let $R(x,i) =  \frac {x^i\cdot Z(x)}{\delta}$. Each element of $CRShz$ is $R((x=\tau),i)$ multiplied by $G_1$ for increasing values of $i$ - i.e. each element is the Commitment of $R(x)$ for increasing values of $i$</p>

<p>$Z(x)$ is of degree $n$ &amp; the max degree of $x$ we multiply it by is $n-2$, so we require $\tau$ powers up to $2n-2$ in $CRS1$ to compute $CRShz$.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CRShz</span><span class="o">=</span><span class="p">[]</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">n</span><span class="o">-</span><span class="mi">2</span><span class="p">):</span>
    <span class="no">CRShz</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">commit</span><span class="p">(((</span><span class="n">x</span><span class="o">^</span><span class="n">i</span><span class="p">)</span><span class="o">*</span><span class="no">Zx</span><span class="p">)</span><span class="o">/</span><span class="n">d</span><span class="p">,</span><span class="no">CRS1</span><span class="p">))</span>

<span class="no">CRShz</span>
<span class="p">[(</span><span class="mi">5282</span> <span class="p">:</span> <span class="mi">2807</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">728</span> <span class="p">:</span> <span class="mi">800</span> <span class="p">:</span> <span class="mi">1</span><span class="p">),</span> <span class="p">(</span><span class="mi">1202</span> <span class="p">:</span> <span class="mi">4268</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)]</span>
</code></pre></div></div>

<p>So having $CRS1$ up to $2n-2$ enables us to split the Trusted Setup into 2 parts - Phase 1 which is the <strong>Universal Setup</strong> &amp; Phase 2 which is the <strong>Circuit Specific Setup</strong>. Phase 1 can be reused for any other circuit as long it has $n$ or less gates.</p>

<p>$\alpha, \beta, \gamma$ &amp; $\delta$ are destroyed after Phase 2 is over.</p>

<h3 id="prover-phase">Prover Phase</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## Prover samples 2 random numbers</span>
<span class="n">r1</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">244</span><span class="p">)</span>
<span class="n">r2</span> <span class="o">=</span> <span class="no">Fp</span><span class="p">(</span><span class="mi">250</span><span class="p">)</span>
</code></pre></div></div>

<p>Prover computes the follow three commitments</p>

<p>$1)\space[A]_1$ where $A = L + \alpha + r_1\delta$</p>

<p>(We have already computed the commitment of $L$ earlier directly from the polynomial $L$ )</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CA1</span> <span class="o">=</span> <span class="no">CL1</span> <span class="o">+</span> <span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">r2</span><span class="o">*</span><span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

<span class="no">CA1</span>
<span class="p">(</span><span class="mi">4720</span> <span class="p">:</span> <span class="mi">3593</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>
<p>$2)\space[B]_2$ where $B = R + \beta + r_2\delta$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CB2</span> <span class="o">=</span> <span class="no">CR2</span> <span class="o">+</span> <span class="no">CRSTrap2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="n">r2</span><span class="o">*</span><span class="no">CRSTrap2</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

<span class="no">CB2</span>
<span class="p">(</span><span class="mi">4544</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1851</span> <span class="p">:</span> <span class="mi">7516</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">2019</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>$3)\space[C]_1$ where $C = \frac {\beta L_p + \alpha L_p + O_p + HZ} {\delta} + L_1 r_2 + R_1 r_1 - r_1 r_2 \delta$</p>

<p>There are 4 terms in the Right Hand Side, we compute each one &amp; add all of them together.</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">com1</span> <span class="o">=</span> <span class="no">ExtEq</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">])</span>

<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">len</span><span class="p">(</span><span class="no">CRSPrv</span><span class="p">)):</span>
    <span class="n">com1</span> <span class="o">=</span> <span class="n">com1</span> <span class="o">+</span> <span class="no">S</span><span class="p">[</span><span class="n">i</span><span class="o">+</span><span class="mi">2</span><span class="p">]</span><span class="o">*</span><span class="no">CRSPrv</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

<span class="c1">## Commitment of (H(x)T(x))/d</span>
<span class="n">com1</span> <span class="o">=</span> <span class="n">com1</span> <span class="o">+</span> <span class="n">commit</span><span class="p">(</span><span class="no">Hx</span><span class="p">,</span><span class="no">CRShz</span><span class="p">)</span>

<span class="n">com2</span> <span class="o">=</span> <span class="n">r2</span><span class="o">*</span><span class="no">P1</span>

<span class="c1">## Remember R = Rx + b + r2*d</span>

<span class="n">com3</span> <span class="o">=</span> <span class="n">r1</span><span class="o">*</span><span class="p">(</span><span class="n">commit</span><span class="p">(</span><span class="no">Rx</span><span class="p">,</span><span class="no">CRS1</span><span class="p">)</span> <span class="o">+</span> <span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">+</span> <span class="n">r2</span><span class="o">*</span><span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">2</span><span class="p">])</span>

<span class="n">com4</span> <span class="o">=</span> <span class="n">r1</span><span class="o">*</span><span class="n">r2</span><span class="o">*</span><span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>

<span class="no">CC1</span> <span class="o">=</span> <span class="n">com1</span> <span class="o">+</span> <span class="n">com2</span> <span class="o">+</span> <span class="n">com3</span> <span class="o">-</span> <span class="n">com4</span>

<span class="no">CC1</span>
<span class="p">(</span><span class="mi">7474</span> <span class="p">:</span> <span class="mi">3237</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>
<p>The only thing to explain in the above is possibly the commitment of $H\cdot Z$</p>

<p>When we have 2 polynomials $H$ &amp; $Z$ &amp; we need to commit their product, then there are 2 ways this can be done (both will obviously result in the same commitment)</p>

<p>$1)$ Prover multiplies $H$ &amp; $Z$ &amp; gets $P = H\cdot Z$ - the degree of $P$ is the degree of $H$ + degree of $Z$</p>

<p>Prover computes the commitment of $P$</p>

<p>$2)$ First, we evaluate $Z$ at $x = \tau$ which gives us a value $z = Z(\tau)$</p>

<p>Now we multiply $H$ by the value $Z(\tau)$ we get a new polynomial whose degree is same as that of $H$.</p>

<p>In our case ($H(x) = 139x^2+480x+210$) the new polynomial</p>

<p>$Z(\tau)\cdot H(x) = Z(\tau)\cdot 139x^2 + Z(\tau)\cdot480x + Z(\tau)\cdot210$</p>

<p>The commitment of $Z(\tau)\cdot H(x)$ is</p>

<p>$[HZ]_1 = Z(\tau)\cdot 139\tau^2\cdot G1 + Z(\tau)\cdot480\cdot \tau\cdot G1 + Z(\tau)\cdot210\cdot G1$</p>

<p>Rearranging,</p>

<p>$[HZ]_1 = 139\cdot(\tau^2\cdot Z(\tau)\cdot G1) + 480\cdot (\tau^1\cdot Z(\tau)\cdot G1) + 210\cdot (\tau^0\cdot Z(\tau)\cdot\ G1)$</p>

<p>The terms in the brackets are exactly what we have in $CRShz$</p>

<p>So,
$[HZ]_1 = 139\cdot CRShz[2] + 480\cdot  CRShz[1] + 210\cdot  CRShz[0]$</p>

<p>This is the same as the commitment of $H$ using $CRShz$ as the Powers of $\tau$ instead of using $CRS1$ as the Powers of $\tau$.</p>

<p>I will explain a little later why we compute the commitment of $HZ$ this way instead of the other simpler way.</p>

<p>Prover sends the proof $\pi = ([A]_1, [B]_2, [C]_1)$ to the verifier</p>

<h3 id="verification-phase">Verification Phase</h3>

<p>Verifier needs the remaining commitments $[I]_1,[\alpha]_1, [\beta]_2, [\gamma]_2 [\delta]_2$ to verify the proof.</p>

<p>Verifier computes $[I]_1$ where  $I = (\frac {\beta L_v + \alpha L_v + O_v}{\gamma})$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">CI1</span> <span class="o">=</span> <span class="no">ExtEq</span><span class="p">([</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">])</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="no">CI1</span> <span class="o">=</span> <span class="no">CI1</span> <span class="o">+</span> <span class="no">S</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">CRSPub</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

<span class="no">CI1</span>
<span class="p">(</span><span class="mi">1657</span> <span class="p">:</span> <span class="mi">1925</span> <span class="p">:</span> <span class="mi">1</span><span class="p">)</span>
</code></pre></div></div>

<p>The remaining are already in the CRS</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Ca1</span> <span class="o">=</span> <span class="no">CRSTrap1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="no">Cb2</span> <span class="o">=</span> <span class="no">CRSTrap2</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="no">Cg2</span> <span class="o">=</span> <span class="no">CRSTrap2</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="no">Cd2</span> <span class="o">=</span> <span class="no">CRSTrap2</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
</code></pre></div></div>

<p>Verifier checks the equality using Pairings</p>

<p>$e([A]_1, [B]_2) \stackrel {?}{=} e([\alpha]_1, [\beta]_2) \cdot e(I, [\gamma]_2) \cdot e([C]_1, [\delta]_2)$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## Left Pairing</span>
<span class="no">CA1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">CB2</span><span class="p">,</span> <span class="nb">p</span><span class="p">)</span>
<span class="mi">2416</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1193</span>

<span class="c1">## Right Pairings</span>
<span class="no">Ca1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">Cb2</span><span class="p">,</span> <span class="nb">p</span><span class="p">)</span> <span class="o">*</span> <span class="no">CI1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">Cg1</span><span class="p">,</span> <span class="nb">p</span><span class="p">)</span> <span class="o">*</span> <span class="no">CC1</span><span class="p">.</span><span class="nf">weil_pairing</span><span class="p">(</span><span class="no">Cd2</span><span class="p">,</span><span class="nb">p</span><span class="p">)</span>
<span class="mi">2416</span><span class="o">*</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1193</span>
</code></pre></div></div>

<p>As you can see, the check verifies</p>

<h3 id="soundness--zero-knowledge">Soundness &amp; Zero Knowledge</h3>

<p>The problems we identified earlier in <a href="#problems">here</a> were fixed by the changes we made <a href="#fixing-problems">here</a>. Below I do some handwaving which tries to explain the intuition behind how these changes fixed the problems.</p>

<p>In our original proof, we had 5 polynomials $L, R, O, H, Z$ &amp; their commitments were all computed by the Prover.</p>

<ul>
  <li>
    <p>We had no way of confirming if she used the QAP &amp; the Solution vector at all in coming up with polynomials &amp; the computing their commitments. She could have used the $k_1, k_2$ trick we showed in the problems section.</p>

    <p><strong>Fix:</strong> Now some of the commitments are computed by the Prover &amp; some by the Verifier &amp; they have common elements - for e.g. the commitment of $I = (\frac {\beta L_v + \alpha L_v + O_v}{\gamma})$ is computed by the Verifier &amp; $I$ includes public parts of $L, R$ &amp; $O$ (i.e. $L_v, R_v$ &amp; $O_v$) - so, if the Prover tried the $k_1, k_2$ the parts computed by the verifier equation won’t match &amp; the check will fail</p>
  </li>
  <li>
    <p>Polynomials $L, R$ &amp; $O$ are formed by multiplying the 3 $QAP$ matrices with the Solution Vector $S$. We have no way for confirming if she used consistent values from the Witness part of $S$ in computing $L$, $R$ &amp; $O$</p>

    <p><strong>Fix:</strong> The shifting of $L$ &amp; $R$ with $\alpha$ &amp; $\beta$ ensures that $L, R$ &amp; $O$ are consistent in using the same $S$ The product $\alpha\cdot\beta$ in the verification equation computed by the verifier guarantees that $A$ and $B$ involve non-trivial $\alpha$ and $\beta$ components. The product $A\cdot B$ now involves a linear dependence on $\alpha$ and $\beta$, and the Groth16 paper presents a proof of how this means this linear dependence can only be balanced out by a $C$ with a consistent choice of $S$ in all three of $L, R$ &amp; $C$ used to compute $A, B$ &amp; $C$.</p>
  </li>
  <li>
    <p>We had no way of confirming that the solution vector used by the Prover had the same Public Input which we expect (i.e. the $out$)</p>

    <p><strong>Fix:</strong> Our modified equation has the public input divided by $\gamma$ ($\gamma$ is not known to the Prover). So, if the Prover used different public inputs in computing $L, R$ or $O$ then it won’t be balanced out by the part computed by the Verifier.</p>
  </li>
  <li>
    <p>We had no way of confirming that the Prover used the right polynomial $Z$ computing the commitment of $H\cdot Z$</p>

    <p><strong>Fix:</strong> The term $C$ contains $\frac {H\cdot Z}{\delta}$ - however, the prover doesn’t know the value of $\delta$. So, if the prover has to compute the commitment using $CRShz$ which has the $\frac{\tau^i\cdot Z(\tau)}{\delta}$ commitments. Any  commitment of $C$ which is sent by the Prover won’t balance out the remaining terms (parts of which are computed by the verifier), unless she computed it using $CRShz$</p>
  </li>
  <li>
    <p>Zero Knowledge: Adding $\alpha, \beta, \gamma, \delta$ ensures that the Prover uses the QAP with the Instance &amp; the Witness. However, now it’s no longer zero knowledge because someone can try to brute force it - i.e. do an exhaustive search of witness permutations combined with the public parts &amp; the $QAP$ &amp; compute each of their commitments &amp; check if the commitments match with the commitments sent by the Prover.</p>

    <p><strong>Fix:</strong> The 2 random values sampled &amp; used by the Prover $r_1$ and $r_2$ randomizes the proof to get zero-knowledge.</p>
  </li>
</ul>

<p>In the Groth16 protocols, the commitments are never opened at some random point given by the Verifier - the proof doesn’t depend on that - it is sound even without the openings.</p>

<p>This ends the post.</p>

<p><strong>Note:</strong> If you are interested in a python implementation, you can check out Crypto Fairy’s excellent series of <a href="https://medium.com/coinmonks/under-the-hood-of-zksnark-groth16-protocol-2843b0d1558b">Blog Posts on Groth16</a></p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FGroth16%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[Groth16 is a zkSNARK protocol introduced by Jens Groth in 2016 &amp; it saw an early application in ZCash. Its proof size is among the smallest (consisting of only three elliptic curve elements) and it is also the fastest to verify]]></summary></entry><entry><title type="html">Sum-Check Protocol and Multilinear Extensions (MLEs)</title><link href="https://risencrypto.github.io/Sumcheck/" rel="alternate" type="text/html" title="Sum-Check Protocol and Multilinear Extensions (MLEs)" /><published>2024-01-31T00:00:00+00:00</published><updated>2024-01-31T00:00:00+00:00</updated><id>https://risencrypto.github.io/Sumcheck</id><content type="html" xml:base="https://risencrypto.github.io/Sumcheck/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<script type="text/x-mathjax-config">
MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
  MathJax.Hub.Insert(MathJax.InputJax.TeX.Definitions.macros,{
    cancel: ["Extension","cancel"],
    bcancel: ["Extension","cancel"],
    xcancel: ["Extension","cancel"],
    cancelto: ["Extension","cancel"]
  });
});
</script>

<h3 id="the-sum-check-protocol">The Sum-Check Protocol</h3>

<p>$g$ is a $v$-variate polynomial defined over a Field $\mathbb F$.</p>

\[\\
u = \sum_{x_1 \in \lbrace 0,1 \rbrace} \sum_{x_2 \in \lbrace 0,1 \rbrace} ... \sum_{x_v \in \lbrace 0,1 \rbrace} g(x_1, x_2, ..., x_v)
- (Eq\space I) \\\]

<p>The above equation sums $g$ over all possible Boolean inputs. The Prover ($\mathcal P$) claims that the sum is $u$. The Sum-Check protocol allows $\mathcal P$ to convince a Verifier ($\mathcal V$) that she has computed the sum correctly.</p>

<p>The steps in the protocol</p>

<p>$(1)$ $\mathcal P$ sends the value $u$ which she claims as the sum, to $\mathcal V$</p>

<p>$(2)$ $\mathcal P$ then sends a univariate polynomial $g_1$ in $x_1$ to $\mathcal V$. $\mathcal P$ claims it’s been created by summing $g$ in all variables except $x_1$ i.e. computing the following sum keeping $x_1$ free</p>

\[\\
g_1(x_1) = \sum_{x_2 \in \lbrace 0,1 \rbrace}  ... \sum_{x_v \in \lbrace 0,1 \rbrace} g(x_1, x_2, ..., x_v)
\\\]

<p>$\qquad$ The right hand side above is the same expression as the right hand side in Expression (I) at the start except with the summation over $x_1$ removed.</p>

\[\\
\bcancel{\color{red}{\sum_{x_1 \in \lbrace 0,1 \rbrace}}} \sum_{x_2 \in \lbrace 0,1 \rbrace} ... \sum_{x_v \in \lbrace 0,1 \rbrace} g(x_1, x_2, ..., x_v) 
\\\]

<p>$\qquad$ $Eq \space I$ results in a value in the left hand side because all variables were evaluated. Where $g_1$ becomes a univariate polynomial in $x_1$ instead of a value because $x_1$ is not summed for all values in $x_1 \in \lbrace 0,1 \rbrace$</p>

<p>$(3)$ $\mathcal V$ checks if $degree(g_1) &lt;= degree(g)$. If not, $\mathcal V$ rejects the proof.</p>

<p>$(4)$ $\mathcal V$ then checks the one summation which was omitted by $\mathcal P$ while creating $g_1$. Doing that omitted summation should result in $u$</p>

<p>i.e. check if $\sum_{x_1 \in \lbrace 0,1 \rbrace} g_1(x_1) \stackrel {?}{=}u $</p>

<p>So he computes $g_1(0) + g_1(1)$ &amp; checks if it sums to $u$.</p>

<p>If it does sum to $u$, then $\mathcal V$ can believe that $g$ also actually totals up to $u$ (which is the claim he is verifying) as long as he is sure that $g_1$ was indeed constructed the way described above (in Step $(2)$)</p>

<p>Let’s assume there is a polynomial $s_1$ which was actually created that way. i.e.</p>

\[\\
s_1(x_1) = \sum_{x_2 \in \lbrace 0,1 \rbrace} ... \sum_{x_v \in \lbrace 0,1 \rbrace} g(x_1, x_2, ..., x_v)
\\\]

<p>$\mathcal V$ has to verify that $g_1 = s_1$. He can do this by picking a random element $r_1 \in \mathbb F$ &amp; verifying if $g_1(r_1) \stackrel {?}{=} s_1(r_1)$ (<a href="/Kate/#the-schwartz-zippel-lemma">Schwartz-Zippel Lemma</a>)</p>

<p>The complexity of creating $s_1$ &amp; evaluating $s_1(r_1)$ isn’t much lesser than evaluating the original $g$ polynomial for all inputs &amp; checking if it equals $u$. If $\mathcal V$ were to do this, he could as well herself calculate $g$ instead of getting it done by $\mathcal P$.</p>

<p>So instead, $\mathcal V$ checks if $s_1(r_1) \stackrel {?}{=} g_1(r_1)$ recursively as shown below.</p>

<p>$(5)$ $\mathcal V$ choses a random element $r_1 \in \mathbb F$ &amp; sends it to $\mathcal P$</p>

<p>$(6)$ Just like $\mathcal P$ created $g_1$ by summing $g$ in all variables except $x_1$, now $\mathcal P$ creates $g_2$ by replacing $x_1$ in $g$ with the value $r_1$ &amp; summing $g$ with $x_2$ free/unevaluated i.e. $x_1 = r_1$, $x_2$ free/unevaluated &amp; but expanding all possible values of $x_3$ to $x_v$.</p>

<p>This creates a univariate polynomial $g_2(x_2)$. $\mathcal P$ sends $g_2$ to $\mathcal V$</p>

<p>$(7)$ $\mathcal V$ checks the degree of $g_2$ &amp; rejects if not correct.</p>

<p>$(8)$ $g_2$ is built with $x_1 = r_1$ &amp; $x_2$ kept free. So $\mathcal V$ needs to check if $g_1(x_1 = r_1) \stackrel {?}{=} g_2(x_2 = 0) + g_2(x_2=1)$</p>

<p>i.e. check if $g_1(r_1) \stackrel {?}{=} g_2(0) + g_2(1)$  &amp; reject if not.</p>

<p>If it checks out, then all $\mathcal V$ needs to do is verify that $g_2$ indeed has been constructed correctly as described. So he continues the recursion as done below.</p>

<p>$(9)$ We have seen 2 rounds above already. Steps $(5)$ to $(8)$ are repeated for $j = 3$ to $j=v-1$</p>
<ul>
  <li>$\mathcal V$ choses a random element $r_{j-1} \in \mathbb F$ &amp; sends it to $\mathcal P$</li>
  <li>$\mathcal P$ creates the univariate polynomial $g_j(x_j)$ by keeping $x_j$ free and $x_1$ to $x_{j-1}$ fixed at $r_1$ to $r_{j-1}$ respectively</li>
</ul>

\[\\
\qquad g_j(x_j) = \sum_{x_{j+1} \in \lbrace 0,1 \rbrace} \sum_{x_{j+2} \in \lbrace 0,1 \rbrace} ... \sum_{x_v \in \lbrace 0,1 \rbrace} g(r_1, r_2, ..., r_{j-1},x_j, x_{j+1},..., x_v)
\\\]

<ul>
  <li>$\mathcal V$ checks the degree &amp; also if $g_{j-1}(r_{j-1}) \stackrel {?}{=} g_j(0) + g_j(1)$</li>
</ul>

<p>$(10)$ In the last round, $\mathcal P$ sends $g_v(x_v)$ to $\mathcal V$. $\mathcal V$ checks degree &amp; if $g_{v-1}(r_{v-1}) \stackrel {?}{=} g_v(0) + g_v(1)$</p>

<p>$(11)$ $\mathcal V$ then picks a random $r_v \in \mathbb F$ &amp; evaluates $g(r_1, r_2, …, r_v)$. $\mathcal V$ also checks if $g_v(r_v) \stackrel {?}{=} g(r_1,r_2,…,r_v)$ &amp; rejects if not.</p>

<p>If it checks out, then it means $g_{v-1}$ is the same polynomial as $s_{v-1}$ i.e. it has been constructed like the $\mathcal P$ said he constructed it. Which in turn means $g_{v-2}$ is the same as $s_{v-2}$. As we keep unrolling, finally, it proves that $g_1$ is equal to $s_1$ which proves the original summation sums up to $u$. This ends the proof.</p>

<h3 id="the-sharpsat-problem">The $\sharp$SAT Problem</h3>

<p>We will run through the Sum-Check protocol using a $\sharp SAT$ example</p>

<p>$(x_1 \space \&amp; \space x_2) \space \&amp; \space(x_3 \space | \space x_4)$</p>

<p>In $\sharp SAT$ you have to check for all possible different combinations of $x_1, x_2, x_3, x_4$ &amp; count how many combinations end up satisfying the above boolean circuit/formula i.e. evaluate  to TRUE(1).</p>

<p>Any boolean formula can be arithmetized &amp; converted into a function by replacing</p>

<ul>
  <li>$A\space \&amp; \space B$ with $A * B$</li>
  <li>$A\space | \space B$ with $(A + B) - (A*B)$</li>
  <li>$! A$ with $1 - A$</li>
</ul>

<p>Arithmetizing the above boolean circuit gives us
$g(x_1, x_2, x_3, x_4) = (1-x_1) x_2 ((x_3 + x_4) - x_3x_4)$</p>

<p>We will walk through the protocol using a sagemath program.</p>

\[\\
\sum_{x_1 \in \lbrace 0,1 \rbrace} \sum_{x_2 \in \lbrace 0,1 \rbrace} \sum_{x_3 \in \lbrace 0,1 \rbrace} \sum_{x_4 \in \lbrace 0,1 \rbrace} g(x_1, x_2, x_3, x_4)
\\\]

<p>We will operate in a Finite Field $\mathbb F_{97}$.  First $\mathcal P$ evaluates $g$ for all possible values of $x_1,x_2,x_3,x_4$ i.e.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="no">R97</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x1</span><span class="p">,</span><span class="n">x2</span><span class="p">,</span><span class="n">x3</span><span class="p">,</span><span class="n">x4</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">F97</span><span class="p">)</span>
<span class="n">g</span> <span class="o">=</span> <span class="no">R97</span><span class="p">((</span><span class="mi">1</span><span class="o">-</span><span class="n">x1</span><span class="p">)</span><span class="o">*</span><span class="n">x2</span><span class="o">*</span><span class="p">((</span><span class="n">x3</span><span class="o">+</span><span class="n">x4</span><span class="p">)</span><span class="o">-</span><span class="n">x3</span><span class="o">*</span><span class="n">x4</span><span class="p">))</span>
<span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">for</span> <span class="n">a1</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
    <span class="k">for</span> <span class="n">a2</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
        <span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
            <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
                <span class="n">sum</span> <span class="o">=</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">g</span><span class="p">(</span><span class="n">a1</span><span class="p">,</span><span class="n">a2</span><span class="p">,</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span>
</code></pre></div></div>

<p>Sum evaluates to $3$</p>

<p>$\mathcal P$ creates a univariate polynomial in $x_1$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">g1</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a2</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
    <span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
        <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
           <span class="n">g1</span> <span class="o">=</span> <span class="n">g1</span> <span class="o">+</span> <span class="n">g</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span><span class="n">a2</span><span class="p">,</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span>
</code></pre></div></div>
<p>If you print out $g_1$,</p>

<p>$g_1(x_1) = -3x1 + 3$</p>

<p>$\mathcal V$ computes $g_1(x_1=0) + g_1(x_1=1)$ &amp; checks if it evaluates to 3.</p>

<p>$\mathcal V$ picks random number $r_1 \in \mathbb F_{97}$, $r_1=25$ &amp; sends it to $\mathcal P$</p>

<p>$\mathcal P$ keeps $x_1=r_1$ &amp; creates the next univariate polynomial $g_2$ keeping $x_2$ free.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">r1</span> <span class="o">=</span> <span class="mi">25</span>
<span class="n">g2</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
    <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
       <span class="n">g2</span> <span class="o">=</span> <span class="n">g2</span> <span class="o">+</span> <span class="n">g</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span><span class="n">x2</span><span class="p">,</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span>
</code></pre></div></div>
<p>This creates $g_2(x_2) = 25x_2$ &amp; is sent to $\mathcal V$</p>

<p>$\mathcal V$ checks if $g_1(x_1=r_1) \stackrel {?}{=} g_2(x_2=0) + g_2(x_2=1)$, which checks out - both LHS &amp; RHS are 25.</p>

<p>Then,</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">r2</span> <span class="o">=</span> <span class="mi">6</span>
<span class="n">g3</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]:</span>
   <span class="n">g3</span> <span class="o">=</span> <span class="n">g3</span> <span class="o">+</span> <span class="n">g</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span><span class="n">r2</span><span class="p">,</span><span class="n">x3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span>
</code></pre></div></div>

<p>$g_3(x_3) = -47x3 - 47$</p>

<p>$g_2(x_2=r_2) = g_3(x_3=0) + g_3(x_3=1) = -44$ - checks out.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">r3</span> <span class="o">=</span> <span class="mi">11</span>
<span class="n">g4</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="n">g</span><span class="p">(</span><span class="n">r1</span><span class="p">,</span><span class="n">r2</span><span class="p">,</span><span class="n">r3</span><span class="p">,</span><span class="n">x4</span><span class="p">))</span>
</code></pre></div></div>

<p>$g_4(x_4) = -15x4 - 32$</p>

<p>$\mathcal V$ picks $r_4=3$</p>

<p>$g_4(x_4=r_4) = -3$</p>

<p>$g(r1,r2,r3,r4) = 94$ (same as $-3 \bmod 97$)</p>

<p>So again checks out &amp; the proof is done.</p>

<h3 id="extension-polynomials-and-multilinear-extensions">Extension Polynomials and Multilinear Extensions</h3>

<p>Let’s say we have a vector $a = [11,7,23,14]$ &amp; we want to encode it into a univariate polynomial, one of the ways to do is to first consider these elements as y-coordinates of points corresponding to $x \in [0,1,2, 3]$ like we did in <a href="/R1CSQAP/#qap">QAP</a>.</p>

<p>We start with a map $f: \lbrace 0,1,2,3 \rbrace \mapsto \lbrace 11,7,23,14 \rbrace$
 &amp; we then use Lagrange Interpolation of the points $[(0,11),(1, 7),(2, 23), (3, 14)]$ to create the polynomial $\tilde f(x) = 41x^3 + 81x^2 + 68x + 11$.</p>

<p>Though we were interested only in inputs of $0,1,2,3$, the polynomial can take all inputs in $\mathbb F_{97}$
i.e. 
$\tilde f(0) = 11, \tilde f(1) = 7, \tilde f(2) =23, \tilde f(3) = 14, \tilde f(4)= 32, \tilde f(5) = 32, …, \tilde f(95) = 65, \tilde f(96)=80$</p>

<p>We started with a vector $a = [11,7,23,14]$ and encoded it into a polynomial whose domain can be considered as a much  larger vector $a’ = [\mathit{11, 7 , 23,14}, 32,32,…,65,80]$</p>

<p>This polynomial $\tilde f$ maps $\mathbb F_{97} \mapsto \mathbb F_{97}$</p>

<p>Hence the polynomial $\tilde f$ is called an <strong>extension</strong> of the original map/function  which mapped just those 4 elements.</p>

<p>If $|a|$ is much smaller than $|a’|$ (i.e size of field is much larger), then it’s called a <strong>low degree extension</strong> (numercial examples in this post do not operate in a very large field, we operate in $\mathbb F_{97}$ for ease of understanding - so these examples don’t actually generate a low degree extension)</p>

<p>The above was a Univariate Polynomial. A Multivariate Polynomial which has a maximum degree of $1$ in each of it’s variables is called as Multilinear Polynomial. For e.g. $2xy + 3x + y$ is a multilinear polynomial but $2x^2 + 3xy + 5$ isn’t multilinear.</p>

<p>For the univariate case, we considered functions/maps whose domain was $\lbrace 0,1,2, …, n-1\rbrace$ which mapped to $\mathbb F$ &amp; we interpolated their extension. In the multivariate case, we will look at functions/maps whose domain is $\lbrace 0, 1 \rbrace^v$ &amp; map it to $\mathbb F$.</p>

<p>In the univariate case, if we had a vector of $n$ values which we wanted to encode in our univariate polynomial, we picked the input domain as $\lbrace 0,1,…,n-1\rbrace$ - like for $a = [11,7,23,14]$ of size $4$, we used the input domain $\lbrace 0, 1, 2,3 \rbrace$. In the multivariate case, for encoding a vector of size $n$, we pick $v=log\space n$ &amp; use $\lbrace 0, 1 \rbrace^v$ as the input domain. $\lbrace 0,1 \rbrace^v$ is called as the $v$-dimensional Boolean Hypercube.</p>

<p><strong>Lagrange Interpolation of a Multilinear Extension (MLE) Polynomial</strong></p>

<p>Let’s encode the same vector $\lbrace 11,7,23,14 \rbrace$ into a multilinear polynomial.</p>

<p>Like before, we start with a map $f: \lbrace 0,1,2,3 \rbrace \mapsto \lbrace 11,7,23,14 \rbrace$.</p>

<p>Our input domain size is 4, so our $v=log(4)=2$. So we use $\lbrace 0, 1 \rbrace^2$. This has 4 values - $0, 1, 2, 3$ - expressing this in binary it becomes $00, 01, 10, 11$. So each element of the input domain has 2 bits - i.e. so we need a bivariate polynomial $\tilde f(x_1,x_2)$ where $x_1$ will take the value of the first bit &amp; $x_2$ the 2nd bit. In general, $x_1$ will take the value of the Most Significant Bit (MSB) &amp; the last $x_v$ will be the LSB.  So if we start with a vector of size $n$, we will end up with a $v$-variate polynomial where $v=log\space n$</p>

<p>For the interpolation, we first calculate the Multilinear Lagrange Basis Polynomials using this formula</p>

\[\\
L_w(x_1, x_2, ..., x_v) =\prod_{i=1}^v(x_iw_i + (1-x_i)(1-w_i)) - (Eq\space II) 
\\\]

<p>$w_i$ is the current bit - for e.g. for the input bitstring $10$, $w_1 = 1, w_2 = 0$</p>

<p>Let’s create $L_{00}$ corresponding to input $0$ (bitstring $00$)</p>

<p>$L_{00} = \prod_{i=1}^2 (x_iw_i + (1-x_i)(1-w_i))$</p>

<p>$\qquad = (x_1w_1 + (1-x_1)(1-w_1)) \cdot (x_2w_2 + (1-x_2)(1-w_2))$</p>

<p>Here, $w_1 = 0$ &amp; $w_2 = 0$</p>

<p>$L_{00} =(1-x_1).(1-x_2) = 1-x_2-x_1+x_1x_2$</p>

<p>For $L_{01}$, $w_1 = 0$ &amp; $w_2 = 1$</p>

<p>$L_{01} = (1-x_1).(x2) = x_2 -x_1x_2$</p>

<p>$L_{10} = x_1 - x_1x_2$</p>

<p>$L_{11} = x_1x_2$</p>

<p>Using the Lagrange basis Polynomials, we can now calculate the Multilinear extension for our map $f: \lbrace 1,2,3, 4 \rbrace \mapsto \lbrace 11,7,23,14 \rbrace$ using the below formula</p>

\[\\
\tilde f(x_1, x_2, ..., x_v) = \sum_{w \in \lbrace 0,1 \rbrace^v} f(w)\cdot L_w(x_1, x_2, ..., x_v) - (Eq\space III)
\\\]

<p>$\tilde f(x_1,x_2) = f(0)\cdot L_{00} + f(1)\cdot L_{01} + f(2) \cdot L_{10} + f(3) \cdot L_{11}$</p>

<p>$\qquad = 11\cdot  (1-x_2-x_1+x_1x_2 ) + 7\cdot (x_2 -x_1x_2) + 23\cdot (x_1 - x_1x_2)+ 14 \cdot (x_1x_2)$</p>

<p>$\qquad = 11-11x_2-11x_1+11x_1x_2 + 7x_2 -7x_1x_2 + 23x_1 - 23x_1x_2 + 14x_1x_2$</p>

<p>$\boldsymbol{\tilde f(x_1,x_2) = 11 + 12x_1 - 4x_2 -5x_1x_2}$</p>

<p>The map $f$ mapped only the input domain  $[0,1,2,3]$ which is same as $(x_1,x_2) = [(0,0), (0,1), (1,0), (1,1)]$, but $\tilde f$ can actually be evaluated for all possible $x_1 \&amp; x_2\space’s \in F_{97}$ - hence it is a multilinear extension of the map.</p>

<p>Here is a sage program to do the same thing which we did manually above</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">=</span> <span class="mi">2</span> <span class="c1">#v-dimensional Boolean hypercube</span>

<span class="n">fmap</span> <span class="o">=</span> <span class="p">[</span><span class="mi">11</span><span class="p">,</span> <span class="mi">7</span><span class="p">,</span> <span class="mi">23</span><span class="p">,</span> <span class="mi">14</span><span class="p">]</span>

<span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="no">Lw</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># Lagrange Basis </span>
<span class="no">R97</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">F97</span><span class="p">,</span> <span class="n">v</span><span class="p">,</span> <span class="p">[</span><span class="n">f</span><span class="s2">"x{i}"</span> <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="n">v</span><span class="o">+</span><span class="mi">1</span><span class="p">)])</span>

<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="n">v</span><span class="p">):</span>
    <span class="n">b</span><span class="o">=</span><span class="no">Integer</span><span class="p">(</span><span class="n">i</span><span class="p">).</span><span class="nf">digits</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="no">None</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> <span class="c1"># pad(ZZ(i).binary(),v)</span>
    <span class="n">g</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
        <span class="n">xi</span> <span class="o">=</span> <span class="no">R97</span><span class="p">.</span><span class="nf">gen</span><span class="p">(</span><span class="n">j</span><span class="p">)</span>
        <span class="n">wi</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="n">v</span><span class="o">-</span><span class="mi">1</span><span class="o">-</span><span class="n">j</span><span class="p">]</span>
        <span class="n">g</span> <span class="o">=</span> <span class="n">g</span><span class="o">*</span> <span class="p">(</span><span class="n">xi</span> <span class="o">*</span> <span class="n">wi</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">xi</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">wi</span><span class="p">))</span>

    <span class="no">Lw</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="n">g</span><span class="p">)</span>

<span class="c1">#MLE</span>
<span class="n">f</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="n">v</span><span class="p">):</span>
    <span class="n">f</span> <span class="o">=</span> <span class="n">f</span><span class="o">+</span> <span class="n">fmap</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">Lw</span><span class="p">[</span><span class="n">i</span><span class="p">]</span>

<span class="nb">print</span><span class="p">(</span><span class="s2">"MLE = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="n">f</span><span class="p">))</span>
</code></pre></div></div>

<p><strong>Note:</strong> Our $g$ polynomial, on which we run the Sum-Check Protocol need not be a multilinear polynomial. In some examples, you will see that it will be a product of multilinear polynomials &amp; the product may not be multilinear. But in most practical cases, $g$ will have a degree at most of $2$ or $3$ in each of it’s variables.</p>

<h4 id="optimisations">Optimisations</h4>

<p>The input to $\mathcal V$ sent by $\mathcal P$ is the values of the map $f[w]\space\forall\space w\space\in\space2^v$. In the Sum-Check Protocol, the verifier has to only evaluate the MLE once at the end at a random point. So it may not be actually necessary for $\mathcal V$ to first compute the MLE &amp; then evaluate it. $\mathcal V$ can instead directly evaluate the MLE without ever forming the polynomial.</p>

<p>Let us say that $\mathcal V$ has to evaluate the MLE at random value $r = r_1, r_2, …, r_v$, he can first compute Lagrange Basis Polynomials using $Eq II$ in the above section on MLE’s using $x_1 = r_1, x_2 = r_2, …$ &amp; then use $Eq III$ directly with the $f$s and the Lagrange Basis polynomials to evaluate the MLEs.</p>

<p>Let’s take an example.</p>

<p>$\mathcal P$ sends $\mathcal V$ the map $f : \lbrace 0,1 \rbrace ^3 \mapsto \mathbb F$ given by $f(0,0,0) = 1, f(0,1,0) = 2, f(1,0,0) = 3,
f(1,1,0) = 4, f(0,0,1) = 5, f(0,1,1) = 6, f(1,0,1) = 7, f(1,1,1) = 8$</p>

<p>$\mathcal V$ has to evaluate the MLE $\tilde f$ at a random point $r = [2,4,6]$ i.e. evaluate $\tilde f(2,4,6)$</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">fmap</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span>
<span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span> <span class="c1"># Random Point</span>
<span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span>

<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="n">v</span><span class="p">):</span>
    <span class="n">b</span><span class="o">=</span><span class="no">Integer</span><span class="p">(</span><span class="n">i</span><span class="p">).</span><span class="nf">digits</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="no">None</span><span class="p">,</span> <span class="n">v</span><span class="p">)</span> 
    <span class="c1"># i'th Lagrange Base </span>
    <span class="no">Lw</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">v</span><span class="p">):</span>
        <span class="n">wi</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="n">v</span><span class="o">-</span><span class="mi">1</span><span class="o">-</span><span class="n">j</span><span class="p">]</span>
        
        <span class="c1"># Eq II to form the Lagrange Basis</span>
        <span class="no">Lw</span> <span class="o">=</span> <span class="no">Lw</span><span class="o">*</span> <span class="p">(</span><span class="n">r</span><span class="p">[</span><span class="n">j</span><span class="p">]</span> <span class="o">*</span> <span class="n">wi</span> <span class="o">+</span> <span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">r</span><span class="p">[</span><span class="n">j</span><span class="p">])</span><span class="o">*</span><span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">wi</span><span class="p">))</span>
    
    <span class="c1">#Eq III </span>
    <span class="n">sum</span> <span class="o">=</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">fmap</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">*</span> <span class="n">g</span>
<span class="nb">print</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</code></pre></div></div>
<p>The above program will print $23$. So $\mathcal V$ has successfully evaluated the MLE without actually forming the MLE.</p>

<p>If you look at the above program carefully, you will notice that it calculates does the multiplications $(1-r_1) \cdot (1-r_2)$, $(r_1\cdot r_2)$, $(1-r_1)\cdot(r_2)$ multiple times. As $v$ becomes larger the number of multiplications which get repeated creates a huge inefficiency. We can use dynamic programming/memoization to optimise it (If you are not familiar with this concept, you can take a look at this video - <a href="https://www.youtube.com/watch?v=e0CAbRVYAWg">Dynamic Programming Tutorial with Fibonacci Sequence</a> )</p>

<p>Let’s first assume $v = 1$ &amp; calculate $L_0$ &amp; $L_1$</p>

<p>$L_0 = (1-r1) = -1$</p>

<p>$L_1 = (r1) = 2$</p>

<p>Next with $v = 2$</p>

<p>$L_{00} = L_0 \cdot (1-r_2) = 3$</p>

<p>$L_{01} = L_0 \cdot r_2 = -4$</p>

<p>$L_{10} = L_1 \cdot (1-r2) =  -6$</p>

<p>$L_{11} =L_1 \cdot r_2 =  8$</p>

<p>With $v=3$</p>

<p>$L_{000} =  L_{00} \cdot (1-r_3) = -15$</p>

<p>$L_{001} = L_{00} \cdot r_3 = 18$</p>

<p>$L_{010} = L_{01} \cdot (1-r_3) =  20$</p>

<p>$L_{011} = L_{01} \cdot r_3 = -4 \cdot 6 = -24$</p>

<p>$L_{100} = L_{10} \cdot (1-r_3) = -4 \cdot (-6) = 30$</p>

<p>$L_{101} = L_{10} \cdot r_3 = -6 \cdot 6 = -36$</p>

<p>$L_{110} = L_{11} \cdot (1-r_3) = 8 \cdot -5 = -40$</p>

<p>$L_{111} = L_{11}\cdot(r_3) = 8 \cdot 6 = 48$</p>

<p>Now we can evaluate the $\tilde f(2,4,6)$ as</p>

<p>$ L_{000}\cdot f(0) + L_{001}\cdot f(1) + L_{010}\cdot f(2) + L_{011}\cdot f(3) + L_{100}\cdot f(4) + L_{101}\cdot f(5) + L_{110}\cdot f(6) + L_{111}\cdot f(7)$</p>

<p>which evaluates to 23</p>

<p>The same thing in a program</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">v</span> <span class="o">=</span> <span class="mi">3</span>
<span class="n">fmap</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">,</span><span class="mi">6</span><span class="p">,</span><span class="mi">7</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span>
<span class="n">r</span> <span class="o">=</span> <span class="p">[</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">6</span><span class="p">]</span>
<span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="no">Lw</span> <span class="o">=</span> <span class="p">[[</span><span class="mi">1</span><span class="o">-</span><span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">r</span><span class="p">[</span><span class="mi">0</span><span class="p">]]]</span>

<span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="n">v</span><span class="p">):</span>
    <span class="no">Lwt</span> <span class="o">=</span> <span class="p">[</span><span class="no">F97</span><span class="p">(</span><span class="mi">1</span><span class="p">)]</span><span class="o">*</span><span class="mi">2</span><span class="o">^</span><span class="p">(</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>

    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="p">(</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)):</span> 
        <span class="n">b</span> <span class="o">=</span> <span class="n">f</span><span class="s1">'{i:b}'</span><span class="p">.</span><span class="nf">zfill</span><span class="p">(</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span>
        <span class="n">lsb</span> <span class="o">=</span> <span class="n">b</span><span class="p">[</span><span class="n">j</span><span class="ss">:j</span><span class="o">+</span><span class="mi">1</span><span class="p">]</span>
        <span class="n">rest</span> <span class="o">=</span>  <span class="n">b</span><span class="p">[</span><span class="mi">0</span><span class="ss">:j</span><span class="p">]</span>
        
        <span class="k">if</span> <span class="p">(</span><span class="n">lsb</span> <span class="o">==</span> <span class="s2">"0"</span><span class="p">):</span>
            <span class="no">Lwt</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="no">Lw</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="no">Integer</span><span class="p">(</span><span class="s1">'0b'</span> <span class="o">+</span> <span class="n">rest</span><span class="p">)]</span><span class="o">*</span> <span class="p">(</span><span class="mi">1</span><span class="o">-</span><span class="n">r</span><span class="p">[</span><span class="n">j</span><span class="p">]))</span>
        <span class="ss">else:
            </span><span class="no">Lwt</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="no">Lw</span><span class="p">[</span><span class="n">j</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="no">Integer</span><span class="p">(</span><span class="s1">'0b'</span> <span class="o">+</span> <span class="n">rest</span><span class="p">)]</span><span class="o">*</span> <span class="n">r</span><span class="p">[</span><span class="n">j</span><span class="p">])</span>
        
    <span class="no">Lw</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Lwt</span><span class="p">)</span>

<span class="c1"># Compute f(2,4,6)</span>
<span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="o">^</span><span class="n">v</span><span class="p">):</span>
    <span class="n">sum</span> <span class="o">=</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">fmap</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="o">*</span><span class="no">Lw</span><span class="p">[</span><span class="n">v</span><span class="o">-</span><span class="mi">1</span><span class="p">][</span><span class="n">i</span><span class="p">]</span>

<span class="nb">print</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</code></pre></div></div>

<h3 id="encoding-the-adjacency-matrix-of-a-graph">Encoding the Adjacency Matrix of a Graph</h3>

<p>let’s consider a Graph $G = (U,E)$ where $E$ the set of $k$ edges &amp; $U$ is the set of $n$ vertices numbered from $0$ to $n-1$ i.e. $U = \lbrace 0, 1, 2, …, n-1\rbrace$.</p>

<p>The Adjacency Matrix for this graph is a square matrix $A$ of size $n\times n$ where we interpret the row &amp; column numbers of elements as vertex numbers. If there is an edge between vertex $i$ &amp; vertex $j$ the Matrix Element $A_{ij} = 1$, else $0$.</p>

<p><img align="left" src="/images/Graph.png?raw=true" /></p>

<p>Lets take this graph.The adjacency matrix will be</p>

\[\begin{array}{c|c|c|c|c}
{\text{}} &amp; {\text{Col0}}
&amp; {\text{Col1}} &amp; {\text{Col2}} &amp; {\text{Col3}}
\\\hline
 Row0&amp;0&amp;1&amp;1&amp;1 \\\hline
 Row1&amp;1&amp;0&amp;1&amp;1\\\hline
 Row2&amp;1&amp;1&amp;0&amp;1 \\\hline
 Row3&amp;1&amp;1&amp;1&amp;0
\end{array}\]

<p>The adjacency matrix is a map $f: (row, col) \mapsto \lbrace 0, 1 \rbrace$</p>

<p>Since maximum row or column number is $4$, it can each be represented by $log(n)$ bits i.e.</p>

<p>$f: \lbrace 0, 1 \rbrace^{2} \times \lbrace 0, 1 \rbrace^{2} \mapsto \lbrace 0, 1 \rbrace$</p>

<p>We will interpolate this to an MLE $\tilde f(row,col)$. As said earlier, each row number &amp; column number will take two bits to represent.</p>

<p>i.e. $\tilde f ((r_0,r_1),(c_0, c_1 ))$, where $r_0$ &amp; $r_1$ are the bits of the row number. This is $\tilde f (r_0,r_1,c_0,c_1)$ - i.e. the MLE takes 4 parameters which can be represented by the 4 variables $x_1, x_2, x_3, x_4$.</p>

<p>We will use our earlier program to interpolate the MLE with the following values of $fmap$ &amp; $v$</p>

<p>$fmap =  [0,1,1,1,1,0,1,1,1,1,0,1,1,1,1,0]$</p>

<p>$v = 4$ (2 bits each for row &amp; column number)</p>

<p>Running the program, we get</p>

<p>$\tilde f = -4x_1x_2x_3x_4 + 2x_1x_2x_3 + 2x_1x_2x_4 + 2x_1x_3x_4 + 2x_2x_3x_4 - x_1x_2 - 2x_1x_3 - x_2x_3 - x_1x_4 - 2x_2x_4 - x_3x_4 + x_1 + x_2 + x_3 + x_4$</p>

<p><strong>Caveats in the above example</strong></p>

<p>A graph with $4$ nodes will have an Adjacency Matrix of size $4\times4$ &amp; the row &amp; column numbers will go from $0$ to $3$, so they can be represented in $2$ bits each, so any element in the matrix can be represented as (row, column) with 4 bits  which works fine. But it’s not always so seamless.</p>

<p><img align="left" src="/images/Graph2.png?raw=true" /></p>

<p>Let’s take for example the Adjacency Matrix for this 3 vertex graph. It’s a $3\times 3$ matrix, so row, col numbers are from $0$ to $2$, this still needs $2$ bits. So totally $4$ bits will be needed to represent each element. So we need to convert the $3\times 3$ Adjacency matrix into a $4\times4$ matrix by setting the extra elements as $0$ before we interpolate it into an MLE.</p>

<p>Below you can see how the matrix can be built up into a $4\times 4$ matrix. The elements in yellow are extra elements we added.</p>

<p><img src="/images/AM.png?raw=true" alt="Built up AdjacencyMatrix" /></p>

<p>In general, if you need $v$ bits to represent each element &amp; interpolate a $v$-variate polynomial, then you will need to build up the matrix to have $2^{v}$ elements i.e. a $n\times n$ matrix where $n = \sqrt(2^v)$</p>

<h3 id="counting-triangles">Counting Triangles</h3>

<p>Now, we will use our MLE to count the number of triangles in our 4 vertex graph (Note this is our first graph - the 4-vertex one &amp; not the 3-vertex graph we discussed after that). We have already computed the MLE for this.</p>

<p>$\tilde f = -4x_1x_2x_3x_4 + 2x_1x_2x_3 + 2x_1x_2x_4 + 2x_1x_3x_4 + 2x_2x_3x_4 - x_1x_2 - 2x_1x_3 - x_2x_3 - x_1x_4 - 2x_2x_4 - x_3x_4 + x_1 + x_2 + x_3 + x_4$</p>

<p>Consider any 3 vertices out of the 4 - let’s call them $a,b,c$. These 3 vertices will form a triangle if &amp; only if there is an edge between $a$ &amp; $b$, and an edge between $b$ &amp; $c$ &amp; another between $c$ &amp; $a$. Which means, only if all three of $\tilde f(a,b),\tilde f(b,c), \tilde f(c,a)$ evaluate to 1 - i.e. only if</p>

<p>$\tilde f(a,b)\cdot \tilde f(b,c)\cdot \tilde f(c,a) = 1$</p>

<p>Even if one of the two vertices out of the three doesn’t have an edge between them, then that evaluation of $\tilde f$ with those edges as params will be $0$ i.e. the above multiplication will result in $0$. So the above equation can be used to count the number of triangles in a graph. However, the triangle formed by $3$ edges $(ab)(bc)(ca)$ is the same as that formed by $(ba)(cb)(ac)$ - each triangle can be represented in 6 different ways by $\tilde f$. So to get the count of the total number of triangles in the graph, we have to divide by $6$.</p>

<p>$\frac {1}{6} \times \sum_{a \in \lbrace 0, 1 \rbrace^{2}} \sum_{b \in \lbrace 0, 1 \rbrace^{2}} \sum_{c \in \lbrace 0, 1 \rbrace^{2}} \tilde f(a,b)\cdot \tilde f(b,c) \cdot \tilde f(c,a)$</p>

<p>When $\mathcal P$ computes the above, she will get the answer $24$. And $\frac {1}{6}\times 24 = 4$</p>

<p>So count of triangles in our graph is $4$ which can also be verified visually for a small graph like our 4-vertex graph.</p>

<p>$\mathcal P$ proves this to $\mathcal V$ using the Sum-Check protocol. Since we have already gone through all the steps of the protocol with other examples, I am not discussing each step here but only ones where we do things differently.</p>

<ul>
  <li>$\mathcal P$ doesn’t need to multiply the 3 $\tilde f$’s to create a $g$ before evaluating it or running the Sum-Check protocol. Actually multiplying the $\tilde f$’s makes it more complicated. She can instead evaluate the 3 $\tilde f$’s &amp; then multiply the evaluations to get $24$ which is then divided by $6$ to get $4$. For e.g.</li>
</ul>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sum</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">a1</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
  <span class="k">for</span> <span class="n">a2</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
      <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">a5</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
          <span class="k">for</span> <span class="n">a6</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
             <span class="n">sum</span> <span class="o">=</span> <span class="n">sum</span> <span class="o">+</span> <span class="n">f</span><span class="p">(</span><span class="n">a1</span><span class="p">,</span> <span class="n">a2</span><span class="p">,</span> <span class="n">a3</span><span class="p">,</span> <span class="n">a4</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a3</span><span class="p">,</span> <span class="n">a4</span><span class="p">,</span> <span class="n">a5</span><span class="p">,</span> <span class="n">a6</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a5</span><span class="p">,</span> <span class="n">a6</span><span class="p">,</span> <span class="n">a1</span><span class="p">,</span> <span class="n">a2</span><span class="p">)</span>
      
<span class="nb">print</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</code></pre></div></div>

<ul>
  <li>In step $2$, $\mathcal P$ has to send the univariate polynomial $g_1$ to $\mathcal V$. Again, this can be done without the verifier first creating a $g$.</li>
</ul>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">g1</span> <span class="o">=</span> <span class="no">R97</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="k">for</span> <span class="n">a2</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
  <span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
      <span class="k">for</span> <span class="n">a5</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">a6</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
          <span class="n">g1</span> <span class="o">=</span> <span class="n">g1</span> <span class="o">+</span> <span class="n">f</span><span class="p">(</span><span class="n">x1</span><span class="p">,</span><span class="n">a2</span><span class="p">,</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">,</span><span class="n">a5</span><span class="p">,</span><span class="n">a6</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a5</span><span class="p">,</span><span class="n">a6</span><span class="p">,</span><span class="n">x1</span><span class="p">,</span><span class="n">a2</span><span class="p">)</span>
</code></pre></div></div>
<p>This gives us $g_1 = -4x1^2 + 4x1 + 12$</p>

<p>But there is an even better way to do this. $g_1$ is a polynomial of at most degree $2$, so instead of creating $g_1$ &amp; sending it, $\mathcal P$ can instead send evaluations of $g_1$ at 3 points - i.e. values of $g_1(0)$, $g_1(1)$, $g_1(2)$ &amp; $\mathcal V$ can recreate $g_1$ himself at his end using Lagrange Interpolation for univariate polynomials.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">a1</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">]</span>
<span class="n">sum</span> <span class="o">=</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span>

<span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">len</span><span class="p">(</span><span class="n">a1</span><span class="p">)):</span>
  <span class="k">for</span> <span class="n">a2</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
    <span class="k">for</span> <span class="n">a3</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
      <span class="k">for</span> <span class="n">a4</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
        <span class="k">for</span> <span class="n">a5</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
          <span class="k">for</span> <span class="n">a6</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="mi">2</span><span class="p">):</span>
            <span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">+</span> <span class="n">f</span><span class="p">(</span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">a2</span><span class="p">,</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a3</span><span class="p">,</span><span class="n">a4</span><span class="p">,</span><span class="n">a5</span><span class="p">,</span><span class="n">a6</span><span class="p">)</span> <span class="o">*</span> <span class="n">f</span><span class="p">(</span><span class="n">a5</span><span class="p">,</span><span class="n">a6</span><span class="p">,</span><span class="n">a1</span><span class="p">[</span><span class="n">i</span><span class="p">],</span><span class="n">a2</span><span class="p">)</span>
            
<span class="nb">print</span><span class="p">(</span><span class="n">sum</span><span class="p">)</span>
</code></pre></div></div>

<p>This prints out $[12, 12, 4]$ - i.e. $g_1(0) = 12, g_1(1) = 12, g_1(2) = 4$</p>

<p>When $\mathcal V$ uses univariate Lagrange Interoplation, then he will get the same $g_1 = -4x1^2 + 4x1 + 12$</p>

<p>In all the steps where $\mathcal P$ has to send a univariate $g_i$, she instead sends the appropriate number of  evaluations instead.</p>

<p>Note that the above program has many calculations which are redone repeatedly &amp; hence can be optimized further by dynamic programming.</p>

<p>In the final step of the protocol, $\mathcal V$ has to compute $\tilde f(r_1,r_2)\cdot \tilde f(r_2, r_3)\cdot \tilde f(r_3, r_1)$ where each $r_i$s is a vector of random values - as seen earlier each of the 3 are vectors of size $\log n = v$. We pick $r_1, r_2, r_3 \in \mathbb F^{\log n} \times \mathbb F^{\log n} \times \mathbb F^{\log n}$. In our case, $\log n = v = 2$, so $\mathcal V$ has to pick 6 random numbers say $r_{11}, r_{12}, r_{21}, r_{22}, r_{31}, r_{32}$ - i.e. $r_1$ is the vector $\lbrace r_{11}, r_{12}\rbrace$, $r_2$ the second two and so on. $\mathcal V$ then computes $\tilde f (r_{11}, r_{12}, r_{21}, r_{22}) \cdot \tilde f (r_{21}, r_{22}, r_{31}, r_{32}) \cdot \tilde f (r_{31}, r_{32}, r_{11}, r_{12}) $  which can be done in time linear to the size of the input Matrix.</p>

<p><strong>This post is based on Justin Thaler’s Book <a href="https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.html">Proofs, Arguments, and Zero-Knowledge</a></strong></p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FSumcheck%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">PlonK</title><link href="https://risencrypto.github.io/Plonk/" rel="alternate" type="text/html" title="PlonK" /><published>2023-09-05T00:00:00+00:00</published><updated>2023-09-05T00:00:00+00:00</updated><id>https://risencrypto.github.io/Plonk</id><content type="html" xml:base="https://risencrypto.github.io/Plonk/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<h3 id="prerequisite-topics">Prerequisite Topics</h3>

<p><em>Note:</em> The target audience for this post is someone with a basic knowledge of zkSNARKs in general without knowing much about $\mathcal{P} \mathfrak{lon}\mathcal{K}$. Here is a post about an older SNARK - <a href="/R1CSQAP/">Groth16</a>.</p>

<h4 id="elliptic-curve-pairings">Elliptic Curve Pairings</h4>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$  uses Elliptic Curve Pairings. If you aren’t familiar with Pairings, here is an introduction to <a href="/WeilMOV#what-is-a-bilinear-map">Elliptic Curve Pairings</a>. The MOV attack itself is not relevant to the current post. The same link also contains a brief description of the roots of unity in a finite field which are relevant.</p>

<h4 id="polynomial-commitment-schemes">Polynomial Commitment Schemes</h4>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$ uses the KGZ polynomial commitment scheme. You can read about the <a href="/Kate/">KZG Polynomial Commitment Scheme here</a>. This link also covers the additional additional batch processing protocols not present in the KZG paper but used in $\mathcal{P} \mathfrak{lon}\mathcal{K}$ like the <a href="/Kate/#batch-mode-multiple-polynomials-multiple-points">Batch Mode Multiple Polynomials, multiple points</a></p>

<h4 id="the-schwartz-zippel-lemma">The Schwartz-Zippel Lemma</h4>

<p>Let $f$ be a polynomial from $\mathbb F_p[x]$ of degree less than or equal to $d$. Let $p \approx 2^{256}$ &amp; $d \le 2^{40}$. If we test $f$ at a random value $r \in \mathbb F_p$, then the probability that $f(r) = 0$ would be $\frac {d}{p}$ which for these values of $d$ &amp; $p$ would be very, very small. So, if $f(r) = 0$, then with high probability, $f$ is a zero polynomial (i.e., zero at all points).</p>

<p>This also helps to prove that 2 polynomials are equal. If the 2 polynomials are $f$ &amp; $g$, we create a new polynomial $p(x) = f(x)\space - \space g(x)$.</p>

<p>If we test $p$ at a random $r \in \mathbb F_p$ &amp; $f(r)$ turns out to be $0$, then $p$ is a zero polynomial with very high probability. If $p$ is a zero polynomial, then it obviously means $f = g$</p>

<h3 id="the-example">The example</h3>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$ operates in a field $\mathbb F_p$.</p>

<p>Consider the equation</p>

<p>$x^3 + x + 5 = 73$</p>

<p>We use this equation in our toy example &amp; we use a multiplicative subgroup of $\mathbb F_{97}$</p>

<p>The Prover knows a witness which satisfies this equation &amp; wants to prove to the Verifier that she knows it.</p>

<p>This is the Circuit and its trace for the witness ($x=4$)</p>

<p><img src="/images/Circuit4.png?raw=true" alt="Circuit" /></p>

<p>This circuit will be expressed using Gate Constraints and Copy Constraints.</p>

<h3 id="gate-constraints">Gate Constraints</h3>
<p>This is the Gate Constraint Equation</p>

<p>${q_L}_i\cdot a_i + {q_R}_i\cdot b_i + {q_M}_i\cdot (a_i\cdot b_i) + {q_C}_i + {q_O}_i\cdot c_i = 0$</p>

<p>Here $i$ takes values from the set $[n] = \lbrace1, 2, 3, …, n\rbrace$ - i.e., depending on the gate.
The $a$s &amp; the $b$s represent the left &amp; right input of the $i$th gate &amp; the $c$s represents the corresponding output.</p>

<p>The $q$’s are known as the selectors. For an addition gate, $q_L$ &amp; $q_R$ will be set to $1$ while $q_M$ will be set to $0$. $q_C$ represents the constant if any in the equation</p>

<p>Likewise for a multiplication gate, $q_L$ &amp; $q_R$ will be set to $0$ while $q_M$ will be set to $1$</p>

<p><strong>Gate 1:</strong></p>

<p>Gate 1 is a multiplication Gate representing</p>

<p>$4 \times 4 = 16$</p>

<p>The Gate Constraint values for this would be</p>

\[\begin{array} {|r|r|}\hline 
{q_L}_1 &amp; {q_R}_1 &amp; {q_M}_1 &amp; {q_C}_1 &amp; {q_O}_1 \\ \hline 
0 &amp; 0 &amp; 1 &amp; 0 &amp; -1 \\ \hline  
\end{array}\]

\[\begin{array} {|r|r|}\hline 
a_1 &amp; b_1 &amp; c_1 \\ \hline 
4 &amp; 4 &amp; 16 \\ \hline  
\end{array}\]

<p>$0\cdot 4 + 0\cdot 4 + 1 \cdot (4\cdot 4) + 0 + (-1)\cdot 16 = 0$</p>

<p><strong>Gate 2</strong></p>

<p>$16 \times 4 = 64$</p>

<p>$0\cdot 16 + 0\cdot 4 + 1 \cdot (16\cdot 4) + 0 + (-1)\cdot 64 = 0$</p>

<p><strong>Gate 3</strong></p>

<p>Gate 3 is an addition gate representing</p>

<p>$64 + 4 = 68$</p>

<p>$1.64+1.4 + 0\cdot (64\cdot4) + 0 + (-1)\cdot 68 = 0$</p>

<p><strong>Gate 4</strong></p>

<p>$68 + 5 - 73 = 0$</p>

<p>$1.68+ 0.0 + 0\cdot (68\cdot0) + 5 + (-1)\cdot 73 = 0$</p>

<p>We can collect all $q$s, $a$s, $b$s &amp; $c$s into vectors.</p>

<p>$q_L = [0, 0, 1, 1]$</p>

<p>$q_R = [0, 0, 1, 0]$</p>

<p>$q_M = [1, 1, 0, 0]$</p>

<p>$q_C = [0, 0, 0, 5]$</p>

<p>$q_O = [-1, -1, -1, -1]$</p>

<p>$a = [4, 16, 4, 68]$</p>

<p>$b = [4, 4, 64, 0]$</p>

<p>$c = [16, 64, 68, 73]$</p>

<p>We need to check that the output of each Gate is calculated correctly.</p>

<p>We now interpolate each of these vectors to create a  polynomial representation of that vector. For reasons <a href="/PLONKWHY#multiplicative-subgroup">explained here</a>, $\mathcal{P} \mathfrak{lon}\mathcal{K}$ uses a multiplicative subgroup to represent the gates. In this example, we have 4 gates &amp; so we need a multiplicative subgroup of order 4 formed by a 4th root of unity. We can use the multiplicative subgroup generated by the 4th root of unity  $\omega = 22$ i.e.,  $H = \lbrace 1, \omega, \omega^2, \omega^3 \rbrace$ - $1$ represents Gate 1, $\omega$ represents Gate 2 &amp; so on &amp; so forth.</p>

<p>Let’s interpolate $a = [4, 16, 4, 68]$. We interpolate this as the points $[(1,4), (\omega,16), (\omega^2,4), (\omega^3,68)]$</p>

<p>In sagemath</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="ss">sage: </span><span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="ss">sage: </span><span class="no">R97</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">F97</span><span class="p">)</span>
<span class="ss">sage: </span><span class="err">ω</span> <span class="o">=</span> <span class="no">F97</span><span class="p">(</span><span class="mi">22</span><span class="p">)</span>
<span class="ss">sage: </span><span class="n">pts</span> <span class="o">=</span> <span class="p">[(</span><span class="err">ω</span><span class="o">^</span><span class="mi">0</span><span class="p">,</span><span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="err">ω</span><span class="p">,</span><span class="mi">16</span><span class="p">),</span> <span class="p">(</span><span class="err">ω</span><span class="o">^</span><span class="mi">2</span><span class="p">,</span><span class="mi">4</span><span class="p">),</span> <span class="p">(</span><span class="err">ω</span><span class="o">^</span><span class="mi">3</span><span class="p">,</span><span class="mi">68</span><span class="p">)]</span>
<span class="ss">sage: </span><span class="no">R97</span><span class="p">.</span><span class="nf">lagrange_polynomial</span><span class="p">(</span><span class="n">pts</span><span class="p">)</span>
<span class="mi">5</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">78</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">92</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">23</span>

</code></pre></div></div>
<p>(Note: The ω used here is omega, the 4th root of unity, and not ‘w’ which is the witness).</p>

<p>That gives us $a(X)$.</p>

<p>Interpolating for other vectors also, we get,</p>

<p>$a(X) = 5x^3 + 78x^2 + 92x + 23$</p>

<p>$b(X) = 7x^3 + 16x^2 + 60x + 18$</p>

<p>$c(X) = 83x^3 + 11x^2 + 85x + 31$</p>

<p>This is done in Round 1</p>

<p><img src="/images/R1.png?raw=true" alt="Round 1" /></p>

<p>The term $(b_i X + b_{i+1})z_H(X)$ is added to each for blinding which is explained <a href="/PLONKWHY#blinding">here</a></p>

<p>The selector polynomials are also computed by interpolation from the selector vectors.</p>

<p>$q_L(X) = 67x^3 + 78x + 49$</p>

<p>$q_R(X) = 24x^3 + 73x^2 + 24x + 73$</p>

<p>$q_M(X) = 30x^3 + 19x + 49$</p>

<p>$q_C(X) = 21x^3 + 23x^2 + 76x + 74$</p>

<p>$q_O(X) = 96$</p>

<p>(<strong>Note:</strong> There is also a Public Input Polynomial which is created using Public Variables. The difference between a Public Input &amp; a constant is that the public variable can change every time while constant remains the same for the circuit. Because of this $q_C$ can be preprocessed &amp; reused for the circuit. Pre-processing means it is part of the one-time initial set up computation of the system before the generation of any proofs. The $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper has the Public Input Polynomial $PI(X)$ - I am ignoring it here because it’s treated very similar to $q_C$ except that it cannot be preprocessed.</p>

<p>Using our Gate Constraint Equation, we get the Gate Constraint Polynomial as</p>

<p>$g(X) = a(X)b(X)q_M(X) + a(X)q_L(X) + b(X)q_R(X) + c(X)q_O(X) + qC(X)$</p>

<p>We use this to prove that Gate Constraints are satisfied. While interpolating all these individual polynomials, we used elements of $H$ as the x-coordinate. So, proving that $g(X) = 0$ on all elements of $H$ would prove the Gate Constraints.</p>

<p>If a polynomial is $0$ on all elements of $H$, it would mean that each element of $H$ is a root of the polynomial - i.e., the polynomial is exactly divisible by the vanishing polynomial $z_H(X) = (X-1)(X-\omega)(X-\omega^2)…(X-\omega^{n-1})$</p>

<p>As <a href="/PLONKWHY#multiplicative-subgroup">explained here</a>, this is the same as</p>

<p>$z_H(X) = X^n - 1$</p>

<p>So, the prover can compute $t(X)= \frac {g(X)}{z_H(X)}$ &amp; provide a commitment to $t(X)$ &amp; the opening proof. The prover would be able to do it only $g(X)$ is $0$ on every element of $H$ which will ensure that $g(X)$ is exactly divisible by $z_H(X)$ and that would prove the Gate Constraints.</p>

<p>This is done in Round 3.</p>

<p><img src="/images/R32.png?raw=true" alt="Round 3" /></p>

<p>Instead proving multiple different polynomials (3 different polynomials are added together to form $t(X)$ above) are zero at $H$, $\mathcal{P} \mathfrak{lon}\mathcal{K}$ combines them as linearly independent terms so that proving $t(X) = 0$ proves that each of those 3 polynomials are 0 on $H$. That’s why you see the $\alpha$ terms as <a href="/PLONKWHY#linear-independence">explained here</a>.</p>

<h3 id="copy-constraints">Copy Constraints</h3>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$ also checks the Copy constraints as explained here in a <strong>separate</strong> post on the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ <a href="/PLONKPerm/">Permutation Check</a>.</p>

<h3 id="remaining-rounds">Remaining Rounds</h3>

<p>The Permutation Polynomial contains multiplication of three polynomials of degree $n-1$. So, this will result in a polynomial of degree close to $3n$. Round 3 splits the quotient polynomial $t(X)$ into multiple parts as <a href="/PLONKWHY/#split-polynomials">explained here</a>.</p>

<p><img src="/images/R4.png?raw=true" alt="Round 4" /></p>

<p>Round 4 above is preparation for the <a href="/PLONKWhy/#field-element-reduction-optimisation">Field Element Reduction Optimisation</a>. The prover computes evaluation of a few polynomials which form the quotient polynomial of Round 3 &amp; sends commitments &amp; opening proofs for them to the verifier.</p>

<p><img src="/images/R5.png?raw=true" alt="Round 5" /></p>

<p>The 3 parts of the above screenshot</p>

<p>$(1)$ Round 5 creates the Linearisation Polynomial $r(X)$ using the evaluations sent in Round 4. If you notice, as discussed in the Field Element Optimisation, wherever polynomials in $t(X)$ were multiplied with other polynomials, there one or more of those polynomials are substituted by the evaluation at $\mathfrak{z}$ in $r(X)$ so that the commitments to the remaining polynomials can be added up by the verifier to compute the commitment for $r(X)$ without the prover needing to send him the commitment.</p>

<p>For e.g., the term $a(X)b(X)q_M(X)$ at the beginning of $t(X)$ (in Round 3) - this is a multiplication of 3 polynomials. In round 4, evaluations of $a$ and $b$ at $X = \mathfrak{z}$ were sent to the verifier - i.e., $\bar a = a(\mathfrak{z})$ and $\bar b = b(\mathfrak{z})$.</p>

<p>In the above screenshot, the term $a(X)b(X)q_M(X)$ in $t(X)$ becomes $\bar a\bar b\cdot q_M(X)$ in $r(x)$ so that the commitment for $\bar a\bar b\cdot q_M(X)$ can be computed by multiplying the commitment for $q_M(X)$ by the product of the values  $\bar a$ &amp; $\bar b$. In Round 4, prover also sends $\bar c = c(\mathfrak{z}),\bar s_{\sigma_1} = S_{\sigma_1}(\mathfrak{z}),\bar s_{\sigma_2} = S_{\sigma_2} = (\mathfrak{z}),\bar {z\omega} = z(\mathfrak{z}\omega)$ so that the commitment to $r(X)$ can be computed by the verifier.</p>

<p>$(2)$ The verifier needs to verify that $r(X)=0$ (which will verify that the other polynomials which are combined to form $r(X)$ are $0$ at all elements of $H$. The verifier also needs to verify the evaluations of $a(X), b(X), c(X), S_{\sigma_1}(X)$ &amp; $S_{\sigma_2}(X)$ sent by the prover are correct.</p>

<p>The prover combines $r(X)$ with all these in a linearly independent way using $\lbrace 1, v, v^2, v^3, v^4, v^5 \rbrace$. Since these are all evaluated at $\mathfrak{z}$, we divide the combination with $(1-\mathfrak{z})$ (why is explained in the <a href="/Kate/">KZG post</a>). This creates the opening proof polynomial $W_{\mathfrak{z}}(X)$</p>

<p>$(3)$ If you check $t(X)$, it has both $z(X)$ &amp; $z(X\omega)$ terms. We already have a commitment to $z$ from Round 2. We compute the opening proof polynomial 
$W_{\mathfrak{z}\omega}(X)$ for $z(X)$ at $\mathfrak{z}\omega$.</p>

<p>This ends the prover steps.</p>

<p>The verifier verifies using <a href="/Kate/#batch-mode-multiple-polynomials-multiple-points">KZG batched protocol</a>.</p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FPlonk%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Permutation Check in PlonK</title><link href="https://risencrypto.github.io/PLONKPerm/" rel="alternate" type="text/html" title="Permutation Check in PlonK" /><published>2023-08-16T00:00:00+00:00</published><updated>2023-08-16T00:00:00+00:00</updated><id>https://risencrypto.github.io/PLONKPerm</id><content type="html" xml:base="https://risencrypto.github.io/PLONKPerm/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<p>Like every SNARK, in $\mathcal{P} \mathfrak{lon}\mathcal{K}$, we have to check if Gate Constraints are satisfied. Other than this, there are also Copy Constraints which have to be checked.</p>

<p>Consider the following Circuit &amp; it’s trace for witness $x = 4$<img src="/images/Circuit3.png?raw=true" alt="Circuit" /></p>

<p>The vectors $a$, $b$ &amp; $c$ here would be</p>

<p>$a = [4, 16, 4, 68]$</p>

<p>$b = [4,4,64,5]$</p>

<p>$c = [16,64,68,73]$</p>

<p>As shown by the coloured lines in the trace table next to circuit diagram above, we also need to check copy constraints like</p>

<ul>
  <li>
    <p>left &amp; right input of Gate 1 have the same value</p>
  </li>
  <li>
    <p>left input of Gate 1 &amp; right input of Gate 2 have the same value</p>
  </li>
  <li>
    <p>the output of Gate 1 is the left input of Gate 2</p>
  </li>
</ul>

<p>etc.</p>
<h4 id="checking-permutations-in-a-vector">Checking Permutations in a vector</h4>

<p>Let’s first consider vector $a$ alone - here we have to check that the 1st, &amp; 3rd element are the same.</p>

<p>Let’s represent the permutation with a map $\sigma$</p>

<p>$\sigma(1) = 3$, $\sigma(2) = 2$, $\sigma(3) = 1$, $\sigma(4)= 4$</p>

<p>To check this, let’s create a new vector $a’$ which contains pairs, each pair containing an element of $a$ and along with its index in $a$</p>

<p>$a’ = [(4,1), (16,2),(4,3), (68,4)]$</p>

<p>We also create another vector $a’’$ with pairs, where the 2nd element of the pair is the permutation of the index of the element.</p>

<p>$a’’ = [(4, \sigma(1)), (16, \sigma(2), (4, \sigma(3)), (68, \sigma(4))]$</p>

<p>If we substitute the output of $\sigma$, this becomes</p>

<p>$a’’= [(4,3),(16,2), (4,1), (68,4)]$</p>

<p>Let’s further simplify the 2 vectors by replacing each pair $(p, q)$ with a single element $p+\beta q$ where $\beta$ is a random element selected from the operating field $\mathbb F_{97}$</p>

<p>So now we have the 2 vectors $a’$ &amp; $a’’$ as</p>

<p>$a’ = [4 + 1\beta,\space\space 16+2\beta,\space\space 4+3\beta,\space\space 68+4\beta]$</p>

<p>$a’’= [4 + 3\beta,\space\space 16+ 2\beta,\space\space  4+1\beta,\space\space  68+4\beta]$</p>

<p>By eyeballing these 2 vectors $a’$ &amp; $a’’$, it becomes pretty apparent that these 2 vectors contain the exact same elements, but in different order - the first element of $a’$ is the 3rd element of $a’’$ &amp; vice versa. So now our check reduces to a check of whether $a’$ &amp; $a’’$ are the same vector but in different order - since we have already fixed the map as part of each element, we no longer care about what order the elements are in the 2 vectors.</p>

<p>So how do we check if 2 sets are identical except for the order.</p>

<p>Let’s take a simpler example of 2 vectors $A$ &amp; $B$.</p>

<p>$A = [ 2, 5, 7 ]$</p>

<p>$B = [ 5, 7, 2]$</p>

<p>We need to check if they are permutations of each other - i.e. whether both contain the same elements the same number of times even though they may be in different order.</p>

<p>The naive way to check would be to multiply all elements of each list &amp; compare with product of the other.</p>

<p>i.e. Check if $2\cdot 5\cdot 7 \stackrel {?}{=} 5\cdot 7\cdot 2$</p>

<p>This will work for the above example but will show a false positive for the following pair of vectors</p>

<p>$A = [ 2, 5, 7 ]$</p>

<p>$C = [ 1, 2, 35]$</p>

<p>$2 \cdot 5\cdot 7 \stackrel {?}{=}  1\cdot 2 \cdot 35$ will return true even if two sets aren’t permutations of each other.</p>

<p>To fix this, we add a random element $\gamma \in \mathbb F_{97}$ to each element &amp; then multiply like earlier.</p>

<p>So in the $A, B$ case</p>

<p>$(2 + \gamma)(5 + \gamma)(7 + \gamma) \stackrel {?}{=} (5 + \gamma)(7 + \gamma)(2 + \gamma)$</p>

<p>This will return true like it should.</p>

<p>In the $A, C$ case</p>

<p>$(2 + \gamma) (5 + \gamma)  (7 +\gamma) \stackrel {?}{=}  (1 + \gamma) (2 + \gamma) (35+ \gamma)$</p>

<p>This will return false like it should.</p>

<p>This simple trick of using a random number works for checking whether the 2 sets are permutations of each other.</p>

<p>Let’s add the random number $\gamma$ to each element our vectors $a’$ &amp; $a’’$</p>

<p>$a’ = [4 + 1\beta + \gamma,\space\space 16+2\beta + \gamma,\space\space 4+3\beta + \gamma,\space\space 68+4\beta + \gamma]$</p>

<p>$a’’= [4 + 3\beta + \gamma,\space\space 16+ 2\beta + \gamma,\space\space  4+1\beta + \gamma,\space\space  68+4\beta + \gamma]$</p>

<p>Now by we can multiply all the elements of $a’$ with each other &amp; then do the same for $a’’$ &amp; check if the 2 products are equal</p>

<p>$(4 + 1\beta + \gamma)(16+2\beta + \gamma)(4+3\beta + \gamma)(68+4\beta + \gamma) \stackrel {?}{=}$</p>

<p>$(4 + 3\beta + \gamma)(16+ 2\beta + \gamma)(4+1\beta + \gamma)(68+4\beta + \gamma)$</p>

<p>Or using $\sigma$,</p>

<p>$(4 + 1\beta + \gamma)(16+2\beta + \gamma)(4+3\beta + \gamma)(68+4\beta + \gamma)$</p>

<p>$\stackrel {?}{=}(4 + \sigma(1)\beta + \gamma)(16+ \sigma(2)\beta + \gamma)(4+\sigma(3)\beta + \gamma)(68+\sigma(4)\beta + \gamma)$</p>

<p>This check will prove if the permutation as per the map $\sigma$ is satisfied for our vector $a$.</p>

<p>To simplify the above example, we used gate numbers 1, 2, 3 etc. However, as <a href="/$\mathcal{P} \mathfrak{lon}\mathcal{K}$WHY#multiplicative-subgroup">explained here</a>, $\mathcal{P} \mathfrak{lon}\mathcal{K}$ uses elements of a multiplicative subgroup $H = \lbrace 1, \omega, \omega^2, \omega^3, …, \omega^{n-1} \rbrace$ to number the gates
For the purpose of this example, we have 4 gates &amp; so we need a multiplicative subgroup of order 4 formed by a 4th root of unity. In our toy example, we will operate in $\mathbb F_{97}$ &amp; we can use the multiplicative subgroup generated by the 4th root of unity  $\omega = 22$</p>

<p>i.e. $H = \lbrace 1, \omega, \omega^2, \omega^3 \rbrace$ 
or if we are writing values $H = \lbrace 1, 22,96,75\rbrace$.</p>

<p>Let’s say we have a polynomial, $a(X)$ created from the vector $a$ such that if you pass the gate number to the polynomial, it will give you value of the vector at that point. This polynomial can be created using Lagrange Interpolation. For the vector $a = [4, 16, 4, 68]$ we create the polynomial $a(X)$ by interpolating the points $[(1,4), (\omega, 16), (\omega^2, 4), (\omega^3,68)]$</p>

<p>$a(X) = 5x^3 + 78x^2 + 92x + 23$</p>

<p>So instead of the check containing elements like $4 + 1\beta + \gamma$,$16+2\beta + \gamma$ etc, we can replace the gate numbers $1, 2, 3, 4$ with $1,\omega,\omega^2, \omega^3$. We can also replace the values, $4,16$ etc with the polynomial $a(X)$ with $X$ being equal to the gate number.</p>

<p>So, the check for vector $a$ becomes</p>

<p>$(a(1) + 1\beta + \gamma)(a(\omega) +\omega\beta + \gamma)(a(\omega^2)+\omega^2\beta + \gamma)(a(\omega^3)+\omega^3\beta + \gamma)$</p>

<p>$\stackrel {?}{=}(a(1) + \sigma(1)\beta + \gamma)(a(\omega)+ \sigma(\omega)\beta + \gamma)(a(\omega^2)+\sigma(\omega^2)\beta + \gamma)(a(\omega^3)+\sigma(\omega^3)\beta + \gamma)$</p>

<p>This can also be written as</p>

<p>$\prod_{X \in  H} a(X) + X\cdot \beta + \gamma \stackrel {?}{=} \prod_{X \in H} a(X) + \sigma(X)\cdot \beta + \gamma$</p>

<h4 id="checking-permutations-across-multiple-vectors">Checking Permutations across multiple vectors</h4>
<p>The above check considers only vector $a$. However, the constraints aren’t localised to be intra vector, they actually will be inter-vector also - i.e., the output of the 1st gate (from the $c$ vector) needs to be the left input to the 3rd gate (from the $a$ vector) &amp; so on so forth. Assuming $n$ gates, we will have a total of $3n$ elements in the 3 vectors. If we had to index $(a \cup b \cup c)$, we will need $3n$ distinct indexes So we create 2 cosets $k_1H$ &amp; $k_2H$ each of which will be disjoint with the $n$ elements of $H$. So in $(H \cup k_1H \cup k_2H)$, we have $3n$ indexes available for the $3n$ elements. Note however that, these will only be used for indexes. For numbering gates, we need &amp; use only the $n$ elements of $H$. We use gate numbers $1$ to $\omega^{n-1}$ for numbering the $n$ gates. Just like the polynomial $a(X)$, we also interpolate &amp; create polynomials $b(X)$ &amp; $c(X)$ from vectors $b$ &amp; $c$. (Note that the $x$ co-ordinate for the interpolation for even $b$ &amp; $c$ will only the elements of $H$ - it’s only for the $y$ co-ordinates which will use ($H\cup k_1H \cup k_2H$).</p>

<p>Though we had $\sigma: index(a) \mapsto index(a)$, in reality we need 3 maps $\sigma_1, \sigma_2, \sigma_3$ one each for index of elements of vectors $a$, $b$ &amp; $c$, in each of these maps the destination could be any the index of the $3n$ elements.</p>

<p><strong>Perm Check</strong></p>

<p>The index numbers for Left of the Circuit would be the elements of $H$, while those for the right &amp; output would be $k_1H$ &amp; $k_2H$ respectively.</p>

<p>$\prod_{X \in H} (a(X) + X\cdot \beta + \gamma)(b(X) + X\cdot k_1\cdot \beta + \gamma)(c(X) + X\cdot k_2\cdot \beta + \gamma) \stackrel {?}{=} $</p>

<p>$\prod_{X \in H} (a(X) + \sigma_1(X)\cdot \beta + \gamma)(b(X) + \sigma_2(X)\cdot \beta + \gamma)(a(X) + \sigma_3(X)\cdot \beta + \gamma)$</p>

<p>Let’s see how to build &amp; implement this check for our example circuit.</p>

<p>We have our multiplicative subgroup $H = \lbrace 1,\omega,\omega^2, \omega^3\rbrace$ with $\omega = 22$, which can also be written as $\lbrace 1, 22, 96, 75 \rbrace$</p>

<p>We create 2 cosets with $k_1 =2$ &amp; $k_2 = 3$ by multiplying each element of $H$ by $k_1$ &amp; $k_2$  respectively.</p>

<p>coset $k_1H = \lbrace 2, 44, 95, 53\rbrace$</p>

<p>coset $k_2H = \lbrace 3, 66, 94, 31 \rbrace$</p>

<p>As discussed earlier, we have a total of 12 elements &amp; we will use $H’ = H \cup k_1H \cup k_2H$ to index the 12 elements</p>

<p>\(\begin{array} {|r|r|r|r|r|r|}\hline 
\qquad\qquad\qquad\quad\space &amp;\quad\space\space \space vector\space a\quad \space\space\space&amp; \space &amp; \space\space\space\quad vector\space b \quad\space\space\space\space\space  &amp; \space&amp; \quad\space\space vector\space c\space\quad\space\space\space\\ \hline
\end{array}\)
\(\begin{array} {|r|r|r|r|r|r|r|r|r|r|r|r|}\hline 
\qquad\quad\space element \space\space &amp;a_1&amp;a_2&amp;a_3&amp;a_4 &amp; \space&amp;b_1&amp;b_2&amp;b_3&amp;b_4 &amp; \space&amp;c_1&amp;c_2&amp;c_3&amp;c_4 \\ \hline  
\qquad value&amp;4&amp;16&amp;4&amp;68 &amp; \space&amp;4&amp;4&amp;64&amp;5 &amp; \space&amp;16&amp;64&amp;68&amp;73 \\ \hline
H'\space index &amp;1&amp;22&amp;96&amp;75 &amp; \space&amp;2&amp;44&amp;95 &amp; \space53&amp;\space &amp; 3&amp;66&amp;94&amp;31 \\ \hline   
map\space\sigma &amp;96&amp;3&amp;2&amp;94 &amp; \space&amp; 44&amp;1&amp;66&amp;53 &amp; \space&amp;22&amp;95&amp;75&amp;31 \\ \hline  
\end{array}\)</p>

<p>In the above table, the row $H’$ index has the original index of each element (using the 3 cosets) &amp; the map row has the mapped index for that element.</p>

<p>Let’s understand the map using the value $4$.</p>

<ul>
  <li>
    <p>This value appears first in vector $a_1$ (original index $1$). Since the next $4$ is at $a_3$ with index $96$, $a_1$ is mapped to $a_3$ &amp; hence the map $sigma$ in the $a_1$ column is the index of $a_3$ which is $96$.</p>
  </li>
  <li>
    <p>The next $4$ is at $b_1$, so $a_3$ map point’s to $b_1$’s index which is $2$.</p>
  </li>
  <li>
    <p>Next is $b_2$ with index $44$ &amp; hence $b_1$’s map points to   $44$.</p>
  </li>
  <li>
    <p>That’s the last $4$ &amp; hence $b_2$’s map points to the first $4$ ($a_1$) whose index is $1$.</p>
  </li>
</ul>

<p>So we can generate 3 maps, one each for vectors $a$,$b$ &amp; $c$.</p>

<p>$\sigma_1 = \lbrace 96,3,2,94 \rbrace$</p>

<p>$\sigma_2 = \lbrace 44,1,66,53\rbrace$</p>

<p>$\sigma_3 = \lbrace 22,95,75,31\rbrace$</p>

<p>From these, we can use Lagrange Interpolation to compute 3 polynomials $S_{\sigma_1}$, $S_{\sigma_2}$ &amp; $S_{\sigma_3}$</p>

<p>Let’s compute the polynomial $S_{\sigma_1}$ in sagemath.</p>

<p>Our 4 points for interpolation for $S_{\sigma_1}$ can be gathered from the above table as $[(1,96),(22,3),(96,2),(75,94)]$</p>

<p>If you check, each point has $x$ co-ordinate as the elements of $H$ &amp; $y$ co-ordinate as the permuted index from $H’$. For $S_{\sigma_2}$, $S_{\sigma_3}$ also, the $x$ co-ordinate will always be 4 elements of $H$. It’s only the $y$ co-ordinate which will be one of the 12 elements of $H’$.</p>

<p>Let’s create $S_{\sigma_1}$ in sagemath.</p>

<p>(Note we are operating in the field $\mathbb F_{97}$)</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="ss">sage: </span><span class="no">F97</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="mi">97</span><span class="p">)</span>
<span class="ss">sage: </span><span class="no">R97</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">F97</span><span class="p">)</span>
<span class="ss">sage: </span><span class="n">pts</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span><span class="mi">96</span><span class="p">),(</span><span class="mi">22</span><span class="p">,</span><span class="mi">3</span><span class="p">),(</span><span class="mi">96</span><span class="p">,</span><span class="mi">2</span><span class="p">),(</span><span class="mi">75</span><span class="p">,</span><span class="mi">94</span><span class="p">)]</span>
<span class="ss">sage: </span><span class="no">R97</span><span class="p">.</span><span class="nf">lagrange_polynomial</span><span class="p">(</span><span class="n">pts</span><span class="p">)</span>
<span class="mi">8</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">73</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">39</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">73</span>
</code></pre></div></div>
<p>Likewise, we can also interpolate $S_{\sigma_2}$ &amp; $S_{\sigma_3}$</p>

<p>Our Perm Check Equation</p>

<p>$f’(X) = (a(X) + X\cdot \beta + \gamma)(b(X) + X\cdot \beta + \gamma)(c(X) + X\cdot \beta + \gamma)$</p>

<p>$g’(X) =  (a(X) + \sigma_1(X)\cdot \beta + \gamma)(b(X) + \sigma_2(X)\cdot \beta + \gamma)(a(X) + \sigma_3(X)\cdot \beta + \gamma)$</p>

<p>Let $m(X) = \frac {f’(X)}{g’(X)}$</p>

<p>So, what we have to check is if $\prod_{x \in H} m(X) \stackrel {?}{=} 1$</p>

<h4 id="the-permutation-polynomial">The Permutation Polynomial</h4>

<p>Let’s define another polynomial $z(X)$ such that</p>

<ul>
  <li>
    <p>$z(\omega) = 1$ and</p>
  </li>
  <li>
    <p>$z(\omega^i) = \prod_{j=1}^{n-1} m(\omega^j)$ for $i = \lbrace 2, 3, … n \rbrace$</p>
  </li>
</ul>

<p>From the above definition</p>

<p><strong>For i = 2</strong>,</p>

<p>$z(\omega^2) = m(\omega)$</p>

<p><strong>For i = 3</strong>,</p>

<p>$z(\omega^3) = m(\omega)m(\omega^2)$</p>

<p><strong>For i = n-1</strong>,</p>

<p>$z(\omega^{n-1}) = m(\omega)m(\omega^2)…m(\omega^{n-2})$</p>

<p>$i = n$ is the same as $i=0$ because we operating in a multiplicative subgroup of order $n$.</p>

<p><strong>For i = n</strong></p>

<p>$z(\omega^n) = z(1) =  m(\omega)m(\omega^2)…m(\omega^{n-1})$</p>

<p><strong>For i = n+1</strong></p>

<p>$z(\omega^{n+1}) = z(\omega) =  m(1)m(\omega)m(\omega^2)…m(\omega^{n-1})$</p>

<p>The above is the same as</p>

<p>$z(\omega) = \prod_{x \in H} M(x)$</p>

<p>So, we have to prove</p>

<ul>
  <li>
    <p>$z(\omega) = 1$</p>
  </li>
  <li>
    <p>We have to also prove the above steps were followed in building $z(\omega)$ - i.e., the $z$’s were accumulatively as computed above.</p>
  </li>
</ul>

<h4 id="the-proof">The Proof</h4>

<p>Point 6 in Section 5.1 of the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ Paper (Page 22) shows what needs to be done to prove this</p>

<p><img src="/images/Perm.png?raw=true" alt="Perm" />
(Note - They use $Z(a)$ while we use $z(X)$, they use $g$ where we use $\omega$ but it’s the same other than these different names.)</p>

<p>a) $L_1$ is $1$ at $a=1$ &amp; $0$ at all other members of $H$ (by definition of the Lagrange Base). If at $a=\omega$, if $L_1(a)(z(a) - 1) = 0$, then it means $z(\omega) = 1$ - which if true, proves the first condition we are looking to prove.</p>

<p>b) As we go through 6(b) for each element $\in H$, it shows that $z$ has been built up accumulatively - i.e., each $z$ is the previous $z$ multiplied by the previous $m$.</p>

<p>So, proving 6a &amp; 6b would prove our Copy Constraints.</p>

<p>In the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper, this is done in Round 3 (Page 29).</p>

<p><img src="/images/R3.png?raw=true" alt="Round 3" /></p>

<p>Let’s go over only the part marked in red (the others are not part of the permutation check).</p>

<p>The last part of the red box is</p>

<p>$(z(X) -1)L_1(X) \frac {\alpha^2}{z_H}$</p>

<p>Here $z_H$ is the vanishing polynomial i.e.</p>

<p>$z_H(X) = (X-1)(X-\omega)(X-\omega^2)(X-\omega^3),…,(X-\omega^{n-1})$</p>

<p>i.e., $z_H=0$ at every element of the set $H$ - it vanishes at every element of $H$. If a prover wants to prove that a polynomial is zero (vanishes) at every element in a set, she divides the polynomial by the vanishing polynomial for that set. Only if it divides without a remainder will the prover be able to provide a commitment to the quotient of the division. So, if the prover is able to provide a commitment to a polynomial divided by $z_H$ and is able to open the commitment successfully, then it means that polynomial is zero on every element of the set $H$.</p>

<p>So, if the prover is able to do this for $(z(X) -1)L_1(X) \frac {\alpha^2}{z_H}$ (we will discuss the $\alpha$ term separately), it means $(z(X) -1)L_1(X) = 0$ at all points of $H$ including at $\omega$. Which means $(z(\omega) -1) = 0$ (because $L_1(1) = 1$).</p>

<p>Which means $z(\omega) = 1$ which was one of the things ($6(a)$) the prover set out to prove.</p>

<p>Next, let’s look at first 2 polynomials inside the red box in the earlier screenshot.</p>

<p>If we compare it with $f’(X)$ &amp; $g’(X)$ we defined earlier, then the 2 equations can be rewritten as</p>

<p>$+ (f’(X)z(X))\frac {\alpha}{z_H} $</p>

<p>$- (g’(X)z(X\omega))\frac {\alpha}{z_H}$</p>

<p>If we ignore the $\alpha$ &amp; $z_H$ terms this is</p>

<p>$f’(X)z(X) - g’(X)z(X\omega)$</p>

<p>This is the $6(b)$ statement which the prover needs to prove. This is divided by $z_H$ for the same reason. If the provers sends a commitment to this &amp; opens it successfully, then it means that this polynomial is zero at all points of $H$ - i.e, proof for $6(b)$. About the $\alpha$ terms in both, it is <a href="/$\mathcal{P} \mathfrak{lon}\mathcal{K}$WHY#linear-independence">explained here</a>. Instead proving multiple different polynomials are zero at $H$, $\mathcal{P} \mathfrak{lon}\mathcal{K}$ combines them as linearly independent terms, so it can be proven together for all those polynomials.</p>

<h4 id="round-2-notes">Round 2 Notes</h4>

<p>Some notes about the construction of $z(X)$ which happens in Round 2 in the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ Paper</p>

<p>Here is a screenshot of Round 2 from Page 28 of the paper</p>

<p><img src="/images/R2.png?raw=true" alt="Round 2" /></p>

<p>The formula for Lagrange Interpolation is</p>

<p>$z(X) = \sum_{i=0}^{n-1} L_i Y_i$</p>

<p>where $L_i(X)$ is the $i$th Lagrange base.</p>

<p>We have $z(\omega) = 1$</p>

<p>i.e., for $X=\omega$, $Y=1$</p>

<p>$\omega$ is the 2nd element of $H$, so $Y_1 = 1$.</p>

<p>We can rewrite the Lagrange interpolation as</p>

<p>$z(X) =  L_0 Y_0 + L_1 + \sum_{i=2}^{n-1} L_i Y_i$</p>

<p>Again, since the last+1 element is the first element (i.e., $n$ is same as index $0$ in the subgroup), we rewrite this as</p>

<p>$z(X) =   L_1 + \sum_{i=2}^{n} L_i Y_i$</p>

<p>Also, we change the $\sum$ range by using $L_{i+1}$ instead of $L_i$</p>

<p>$z(X) =   L_1 + \sum_{i=1}^{n-1} L_{i+1} Y_{i+1}$</p>

<p>So that’s what is used in the screenshot above. $Y_i$ is replaced by the equation to calculate $Y_i$. The numerator of the equation is the same as the $f’(X)$ we defined earlier &amp; the denominator is $g’(X)$</p>

<p>Also, the term $(b_7 X^2 + b_8 X + b_9)z_H(X)$ is added while computing $z(X)$ for blinding which is explained <a href="/$\mathcal{P} \mathfrak{lon}\mathcal{K}$WHY#blinding">here</a></p>

<p>Thus, we interpolate &amp; compute the Permutation Polynomial $z(X)$. This polynomial is then used in Round 3 as discussed earlier to create a proof for the Copy Constraints.</p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FPLONKPerm%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Few questions answered about PlonK</title><link href="https://risencrypto.github.io/PLONKWHY/" rel="alternate" type="text/html" title="Few questions answered about PlonK" /><published>2023-07-21T00:00:00+00:00</published><updated>2023-07-21T00:00:00+00:00</updated><id>https://risencrypto.github.io/PLONKWHY</id><content type="html" xml:base="https://risencrypto.github.io/PLONKWHY/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<hr />

<h4 id="multiplicative-subgroup">Multiplicative Subgroup</h4>
<p><strong>Q:</strong> Why does $\mathcal{P} \mathfrak{lon}\mathcal{K}$ use a multiplicative subgroup?</p>

<p><strong>A:</strong> There are multiple reasons why $\mathcal{P} \mathfrak{lon}\mathcal{K}$ uses a multiplicative subgroup</p>

<p>$(1)\space$ <a href="/WeilMOV#roots-of-unity">Every element of a finite field is a root of unity</a>. A Finite Field $\mathbb F_p$ has a multiplicative subgroup of order $n$ only if $n$ divides $p-1$. All primitive roots of unity in a finite field also form a multiplicative subgroup of the field. Let $\omega$ be a primitive $n$th root of unity in $\mathbb F_p$ i.e. $\omega^n = 1$ This forms a multiplicative subgroup of order $n$ - let’s call it $H$</p>

<p>$H = \lbrace 1, \omega, \omega^2, \omega^3, …, \omega^{n-1} \rbrace$</p>

<p>This can support a circuit with a maximum of n gates.</p>

<p>In <a href="/R1CSQAP/">Groth16</a> with $n$ gates, we use $\lbrace 1, 2, 3, …, n \rbrace$ to represent the gates. There, we compute the vanishing polynomial as</p>

<p>$z_H(X) = (X-1)\cdot (X-2)\cdot(X-3) \dots \dots(X-n)$ (where 1, 2, 3 etc are the gate numbers)</p>

<p>The number of gates is usually very large (may be a million gates or more). So, computing the vanishing polynomial which has a million such terms is quite expensive.</p>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$ numbers the gates using the elements of the multiplicative subgroup $H$. Now the vanishing polynomial becomes</p>

<p>$z_H(X) = (X-1) \cdot(X-\omega)\cdot (X-\omega^2)\cdot …\cdot (X-\omega^{n-1})$</p>

<p>Now,</p>

<p>Let’s consider the polynomial $X^n - 1$</p>

<ul>
  <li>
    <p>For $X = 1$,</p>

    <p>$1^n = 1$, so $(X-1)$ is a root of $X^n - 1$</p>
  </li>
  <li>
    <p>For $X = \omega$,</p>

    <p>Since $\omega$ is the $n$th root of unity, $X^n = 1$ &amp; hence $\omega$ is a root of $X^n - 1$</p>
  </li>
  <li>
    <p>For $X = \omega^2$</p>

    <p>${\omega^2}^n = {\omega^n}^2 = {1}^2 = 1$.</p>

    <p>So $\omega^2$ is also a root of $X^n - 1$</p>
  </li>
  <li>
    <p>Like this, we can prove that every element of $H$ is a root of $X^n - 1$ &amp; since $X^n - 1$ is degree $n$, the maximum number of roots it can have is $n$.</p>
  </li>
</ul>

<p>So $X^n - 1 = (X-1) \cdot (X-\omega)\cdot (X-\omega^2) \dots \dots  (X-\omega^{n-1})$</p>

<p>So $z_H = X^n - 1$</p>

<p>So now the vanishing polynomial $Z_H$ is very easy to compute instead of having to multiply a million terms.</p>

<p>$(2)$ Using a multiplicative subgroup allows an efficient &amp; elegant Product Check on the subgroup.</p>

<p>Take a look at <a href="/PLONKPerm#the-proof">$\mathcal{P} \mathfrak{lon}\mathcal{K}$’s Permutation proof</a>.</p>

<p>This proof uses</p>

<p>$z(\omega X) = z(X) \cdot m(X) \qquad\qquad$ (where $m(X) = \frac {f’(X)}{g’(X)})$</p>

<p>We can define $z$ so because we are operating in a multiplicative subgroup 
$H = \lbrace 1,\omega, \omega^2, \omega^3, …, \omega^{n-1} \rbrace$, where multiplying by each element  $\omega$ gives us the next element &amp; thus we get the “right shift” relation between $z$ at an element &amp; $z$ at the next element.</p>

<p>$(3)$ Using a multiplicative subgroup of a Finite Field is required for usage of <a href="https://vitalik.ca/general/2019/05/12/fft.html">Fast Fourier Transform</a> to speed up some operations.</p>

<hr />
<h4 id="blinding">Blinding</h4>
<p><strong>Q:</strong> In Round 1 (Page 28 of the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper), random blinding scalars are used to modify the 3 wire polynomials (the polynomials representing the left, right &amp; output of the gates). What exactly is blinding?</p>

<p><strong>A:</strong> Let’s say you have a polynomial $f(X)$ of degree $d$ &amp; it’s commitment $C_f$. Let’s say the verifier selects random value $r$ &amp; the prover sends the evaluation of $f$ at $r$ i.e. $f(r) = z$</p>

<p>A polynomial of degree $d$ can be recreated with $d+1$ evaluations by using Lagrange Interpolation. So, each opening of a Polynomial Commitment leaks some info about the polynomial.</p>

<p>Hence SNARKs use a trick called blinding to make it zero knowledge. Multiply the vanishing polynomial $z_H$ by a random Polynomial $R(X)$ &amp; add it to $f(X)$ to create a new polynomial $F(X)$</p>

<p>$F(X) = R(X)\cdot z_H + f(X)$</p>

<p>Instead of committing and opening $f(X)$, the prover commits &amp; opens $F(X)$.</p>

<p>$z_H$ is zero on the set the constraints are checked on - so on this set $F(X) = f(X)$. So other than in the commitment &amp; opening, the SNARK can continue to use $f$ instead of $F$</p>

<p>The next question is what should be the degree of the random polynomial $R$. That depends on how many points you open $f$ at - if there is an opening at only one point, then $R$ needs to be of minimum degree $1$, if there are two openings, then there $R$ needs to be at least of degree $2$. The new polynomial $F(X)$ which is going to be opened instead of $f(X)$ has to be of degree of $f$ plus the number of points at which $f$ needs to be opened.</p>

<p>In Round 1, the left, right &amp; output polynomials are evaluated only at one point each &amp; hence a random polynomial of degree $1$ is used for blinding - for e.g. for blinding the opening of $a(X)$, $R(X) = (b_1 X + b_2)$ is used as the random polynomial. The round 2 polynomial $z(X)$ is evaluated at 2 points &amp; hence a degree 2 random polynomial $(b_7 X + b_8 X + b_9)$ is used.</p>

<hr />
<h4 id="linear-independence">Linear Independence</h4>
<p><strong>Q:</strong> In Round 3 (Page 29), when combining different polynomials to form $t(X)$, why are different powers of $\alpha$ i.e. $ \alpha^0, \alpha^1, \alpha^2$ used.</p>

<p><strong>A:</strong> Let’s say we have 4 polynomials - $f_1$, $f_2$, $f_3$ &amp; $f_4 \in \mathbb F_p[X]$ where the max degree of these polynomials is $d$ which is very, very small as compared to $p$.</p>

<p>We want to combine them into one polynomial $f$ such that if $f$ is 0 at some point, then all of $f_i$’s are also zero at the same point.</p>

<p>Consider the set ${1, z, z^2, z^3}$
This is a linearly independent set.</p>

<p>We can use this set to combine four variables $a_1, a_2, a_3$ &amp; $a_4$ like this</p>

<p>$g(Z) = a1 + a2\cdot Z + a3\cdot Z^2 + a4\cdot Z^3$</p>

<p>If $g(Z)=0$ at some $Z \ne 0$, then it means $a_1 = a_2 = a_3 = a_4 = 0$ (by the definition of a linearly independent set)</p>

<p>So, we can combine the polynomials $f_i$’s as</p>

<p>$f(X,Z) = f1(Z) + Z\cdot f2(x) + Z^2 \cdot f3(X) + Z^3\cdot f4(X)$</p>

<p>At some  $X = r_1$, let</p>

<p>$f_1(r_1) = a_1$, $f_2(r_1) = a_2$, $f_3(r_1) = a_3$, $f_4(r_1) = a_4$,</p>

<p>So now</p>

<p>$f(X=r_1, X) = a1 + a2\cdot Z + a3\cdot Z^2 + a4\cdot Z^3$</p>

<p>At some random value $r_2$ chosen from $\mathbb F_p$, if</p>

<p>$f(X=r_1, Z = r_2) = 0$</p>

<p>then it means  $a1 = a2 = a3 = a4 = 0$</p>

<p>i.e. $f_1(r_1, r_2) =f_2(r_1, r_2) = f_3(r_1, r_2) =  f_4(r_1, r_2) = 0$</p>

<p>If $f_1$, $f_2$, $f_3$, $f_4$ are all $0$ at some random value $r_2$, then by the Schwartz-Zippel lemma, $f_1$, $f_2$, $f_3$, $f_4$ are all zero polynomials with very high probability because the maximum degree of these polynomials is very, very small as compared to $p$</p>

<p>So if we want to test if multiple polynomials are zero polynomials or not, we combine them using a lineraly independent set so we can test them with just one evaluation at a random point rather than testing them separately. Round 3 in the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper creates the polynomial $t(X)$ with the linearly independent set $[1, \alpha, \alpha^2]$ to do this. In Round 5, the set $\lbrace 1, v, v^2, v^3, v^4, v^5 \rbrace$ is used to combine several polynomials to form a single opening proof polynomial $W_\zeta(X)$. It may be used at other places also.</p>

<hr />
<h4 id="split-polynomials">Split Polynomials</h4>
<p><strong>Q:</strong> Why does the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ protocol split the Quotient Polynomial into 3 polynomials?</p>

<p><strong>A:</strong> In Round 3 (Page 29 of the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ Paper), the Quotient Polynomial $t(X)$ is split into 3 polynomials</p>

<p>$t(X) = t’_{lo}(X) + X^n t’_{mid}(X) + X^{2n}t’_{hi}(X)$</p>

<p>This means 3 commitments are needed instead of one which increases proof size, so why is it done?</p>

<p>The tradeoff is that opening time gets reduced because of having smaller polynomials &amp; hence the prover time gets reduced.</p>

<p>The opening time of a polynomial depends on the degree of the polynomial. However, having smaller polynomials may not help if the 3 polynomials are opened separately . The $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper presents a technique for batched opening of different polynomials at different points (on Page 10) which ensures that the opening time of 3 smaller polynomis is much lower than the opening time of one polynomial of roughly 3 times the size.</p>

<hr />
<h4 id="field-element-reduction-optimisation">Field Element Reduction Optimisation</h4>
<p><strong>Q:</strong> In Round 5 (Page 30), the Linearisation Polynomial $r(X)$ is computed. What exactly is the Linearisation Polynomial?</p>

<p><strong>A:</strong> Let’s look at how one proves the identity $h_1(X)\cdot h_2(X) - h_3(X) = 0$?</p>

<p>The normal way would be for the prover to send commitments for $h_1, h_2, h_3$. Then the verifier chooses a random number $r$ &amp; the prover sends evaluation proofs for the 3 polynomials at $r$. The verifier then checks if $h_1(r)\cdot h_2(r) - h_3(r) \stackrel {?}{=} 0$.</p>

<p>$\mathcal{P} \mathfrak{lon}\mathcal{K}$ uses an optimisation which allows it to send one less evaluation proof.</p>

<p>This optimisation is based on the fact that Polynomial commitments like KZG are additively homomorphic, but not multiplicatively homomorphic.</p>

<p>$F(X) = f_0 + f_1X + f_2X^2 + … + f_dX^d$</p>

<p>$G(X) = g_0 + g_1X + g_2X^2 + … + g_dX^d$</p>

<p>Commitment Reference String = $\lbrace G, aG,a^2G, a^3G, …, a^dG \rbrace$</p>

<p>Commitment of $F$ &amp; $G$ would be</p>

<p>$C_{F} = F(a)\cdot G = (f_0 + f_1a + f_2a^2 + … + f_da^d)\cdot G$</p>

<p>$C_{F} = f_0\cdot G + f_1a\cdot G + f_2a^2\cdot G + … + f_da^d\cdot G$</p>

<p>and</p>

<p>$C_{G} = g_0\cdot G + g_1a\cdot G + g_2a^2\cdot G + … + g_da^d\cdot G$</p>

<p>Now if we have a polynomial</p>

<p>$E(X) = F(X) + G(X) =  f_0 + f_1X + f_2X^2 + … + f_dX^d + g_0 + g_1X + g_2X^2 + … + g_dX^d$</p>

<p>It’s obvious that the commitment for $E$ would be the sum of the commitments for $F$ &amp; $G$</p>

<p>i.e. $C_{E} = C_F + C_G$</p>

<p>However the commitment is not multiplicatively homomorphic, i.e. if $H(X) = F(X) \cdot G(X)$, then you wouldn’t be able to compute the commitment of $H$ from those of $F$ &amp; $G$.</p>

<p>Getting back to how the prover proves the identity $h_1(X)\cdot h_2(X) - h_3(X) = 0$</p>

<p>The prover evaluates $h_1$ at $r$ as $h_1(r) = c$ &amp; sends the evaluation proof for the same. The verifier creates a new polynomial called as the Linearisation Polynomial</p>

<p>$L(X) = c\cdot h_2(X) - h_3(X)$</p>

<p>Because $h_1$ has been replaced by a constant $c$ in $L(X)$, $L$ doesn’t contains a multiplication of two polynomials. Hence the verifier can compute the commitment of $L$ by himself as</p>

<p>$C_L = c\cdot C_{h_2} - C_{h_3}$</p>

<p>where $C_L$, $C_{h_2}$ &amp; $C_{h_3}$ are commitments of $L$, $h_2$ &amp; $h_3$ respectively.</p>

<p>Since the commitment to $L$ has been computed using comittments to $h_2$ &amp; $h_3$, verifying if $L(r) =0$ &amp; $h_1(r) = c$ would be enough for the verifier to verify that $h_1(r)\cdot h_2(r) - h_3(r) {=} 0$. The verifier doesnt need to know the evaluation of $h_2$ &amp; $h_3$ &amp; prover doesn’t need to send the evaluation proofs for $h_2$ &amp; $h_3$.</p>

<p>So instead of sending commitments to $h_1, h_2, h_3$ &amp; evaluation proofs for all 3, the prover needs to send only commitments to $h_1, h_2, h_3$ &amp; evaluation proofs  for $L$ &amp; $h_1$.</p>

<p>(In the $\mathcal{P} \mathfrak{lon}\mathcal{K}$ paper, this is on Page 18 titled “Reducing the number of field elements”).</p>]]></content><author><name>RisenCrypto</name></author><category term="uc" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">R1CS and QAP - From Zero to Hero with Finite Fields &amp;amp; sagemath</title><link href="https://risencrypto.github.io/R1CSQAP/" rel="alternate" type="text/html" title="R1CS and QAP - From Zero to Hero with Finite Fields &amp;amp; sagemath" /><published>2023-02-07T00:00:00+00:00</published><updated>2023-02-07T00:00:00+00:00</updated><id>https://risencrypto.github.io/R1CSQAP</id><content type="html" xml:base="https://risencrypto.github.io/R1CSQAP/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<p>The Prover wants to prove to the Verifier that she knows the solution to a particular equation without revealing the solution itself. In order for her to do this, in the Pinnochio &amp; Groth16 zkSNARKs, she has to first transform the equation into the QAP (Quadratic Arithmetic Program) form. This post explains only the conversion part of these zkSNARKs.</p>

<p>This post is based on Vitalik Buterin’s write up on the same topic (with a partially similar title) but with some changes.</p>

<ul>
  <li>
    <p>In his write up, he doesn’t operate in a finite field though in the real world all these operations are done in a finite field. I think he has avoided finite fields to simplify the write up. However, I think not using finite fields ends up complicating it instead of simplifying it. His examples end up with scary looking floating point numbers. Working a finite field avoids this. Also since floating point operations are not precise, his final $T/Z$ polynomial division which should have no remainder ends up with an infinitesimal remainder if you try it out yourself. We will work in a finite field, $\mathbb F_p = GF(641)$.</p>
  </li>
  <li>
    <p>In the R1CS to QAP part of the transformation &amp; beyond, I have shown the implementation using sagemath.</p>
  </li>
</ul>

<h2 id="the-equation">The equation</h2>

<p>$x^3 + x + 5 = 35$ is the cubic equation the Prover knows the solution to &amp; she has to convince the Verifier about this without revealing the solution to him. The solution is $x=3$</p>

<p>If you were to write a program in Python which takes a value for $x$ &amp; evaluates the computation part of this equation, it would look something like this</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">Evaluate</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="k">return</span> <span class="n">x</span><span class="o">**</span><span class="mi">3</span> <span class="o">+</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">5</span>
</code></pre></div></div>

<h2 id="code-flattening">Code Flattening</h2>

<p>We first decompose the above code into a series of much simpler operations. This step is called flattening.
In the flattened code, we are allowed only the following operations</p>

<ul>
  <li>Assignment i.e. $x = y$, where $x$ is be a variable and $y$ can be a variable or a constant</li>
  <li>Operations like $x = y$ (Operator) $z$, where $x$ is a variable and $y$ and $z$ can be variables or constants. The only operators allowed are $+, -, *, /$</li>
</ul>

<p>There is no return statement in the flattened code. Instead, we assign the return value to a variable “out”.</p>

<p>The flattened code</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">Evaluate</span><span class="p">(</span><span class="n">x</span><span class="p">):</span>
    <span class="n">var1</span> <span class="o">=</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span> 
    <span class="n">var2</span> <span class="o">=</span> <span class="n">var1</span> <span class="o">*</span> <span class="n">x</span> 
    <span class="n">var3</span> <span class="o">=</span> <span class="n">var2</span> <span class="o">+</span> <span class="n">x</span>
    <span class="n">out</span>  <span class="o">=</span> <span class="n">var3</span> <span class="o">+</span> <span class="mi">5</span>
</code></pre></div></div>

<h2 id="conversion-to-arithmetic-circuits--then-r1cs">Conversion to Arithmetic Circuits &amp; then R1CS</h2>

<p>Next, we draw an arithmetic circuit of the above flattened program.</p>

<p><img src="/images/Circuit.png?raw=true" alt="Arithmetic Circuit" /></p>

<p>As we see from the circuit diagram, the circuit has 4 gates representing multiplication &amp; addition operations &amp; also has 5 variables &amp; a constant $5$.</p>

<p>Let’s represent the variables in a solution vector $S$ (also called as witness)</p>

<p>$S = [1, out, x, var1, var2, var3]$</p>

<p>$1$ is included as an element of the vector so as to represent constants. For e.g. if we need a constant $5$, it will be represented as $5 * 1$</p>

<p>We now convert the Arithmetic Circuit into a Rank-1 Constraint System (R1CS). A R1CS is a triple of vectors $(l, r, o)$, and a solution vector $S$, such that $(l\cdot S) * (r\cdot S) = (o\cdot S)$ where $(\cdot)$ is the dot-product. Here $l$ stands for left (or left hand side of the multiplication) &amp; $r$ for right of the multiplication &amp; $o$ for output of each gate. We will have one triplet/constraint for each of the arithmetic gates.</p>

<p><strong>Gate 1</strong></p>

<p>Now in the circuit diagram, let’s take the first gate which represents $var1 = x * x$</p>

<p>For the purpose of the conversion, we look at it as $x *  x = var1$. We now represent it as 3 vectors $l, r, o$. $l$ &amp; $r$ is the vector on the left &amp; right of the gate &amp; $o$ is the output vector.</p>

<p>$l = [0, 0, 1, 0, 0, 0]$ (This represents the term $x$ which is to the left of the multiplication gate.  Every element of the $l$ vector is 0 except the element corresponding to $x$ which has the value 1)</p>

<p>$r = [0, 0, 1, 0, 0, 0]$ (This represents the term $x$ which is to the right of the multiplication gate. Every element of the $r$ vector is 0 except the element corresponding to $x$ which has the value 1)</p>

<p>$o = [0, 0, 0, 1, 0, 0]$ (This represents $var1$ which is the output of the multiplication gate. Every element of the $o$ vector is 0 except the one corresponding to $var1$ which has the value 1)</p>

<p>Any solution vector which is correct will satify $(l.S) * (r\cdot S) = (o\cdot S)$.</p>

<p>Let us try this out. We know the solution of the equation $x^3 + x + 5 == 35$ is $x = 3$. So substitute our solution vector $S = [1, out, x, var1, var2, var3]$ with the actual values based on $x = 3$</p>

<p>$var1 = x *  x = 3 *  3 = 9$</p>

<p>$var2 = var1 *  x = 9 *  3 = 27$</p>

<p>$var3 = var2 + x = 27 + 3 = 30$</p>

<p>$out = var3 + 5 = 30 + 5 = 35$</p>

<p>So $S = [1, 35, 3, 9, 27, 30]$</p>

<p>Dot product of any two vectors $p = [p_1, p_2, …, p_n]$ and $q = [q_1, q_2, …, q_n]$ is defined as</p>

<p>$p \cdot q = \sum_{i=1}^{n} = {p_1}{q_1} + {p_2}{q_2} + … + {p_n}{q_n}$</p>

<p>So $l\cdot S = [0, 0, 1, 0, 0, 0]\cdot[1, 35, 3, 9, 27, 30]$</p>

<p>$l\cdot S = 0 * 1 + 0 * 35 + 1 * 3 + 0 * 9 + 0 * 27 + 0 * 30 = 3$</p>

<p>Likewise $r.S = 3$ and $o.S = 9$</p>

<p>So $(l\cdot S) * (r\cdot S) = 3 * 3 = 9 = (o\cdot S)$.</p>

<p>So $(l\cdot S) * (r\cdot S) = (o\cdot S)$ is satisfied - this is a satisfied R1CS - it shows that the solution vector satisfies <strong>Gate 1</strong></p>

<p><strong>Gate 2</strong></p>

<p>Let’s take the 2nd gate which represents $var1 * x  = var2$</p>

<p>$l = [0, 0, 0, 1, 0, 0]$ (This represents the term $var1$ which is to the left of the multiplication gate.  Every element of the $l$ vector is 0 except the element corresponding to $var1$ which has the value 1)</p>

<p>$r = [0, 0, 1, 0, 0, 0]$ (This represents the term $x$ which is to the right of the multiplication gate. Every element of the $r$ vector is 0 except the element corresponding to $x$ which has the value 1)</p>

<p>$o = [0, 0, 0, 0, 1, 0]$ (This represents the term $var2$ which is the output of the multiplication gate.  Every element of the $o$ vector is 0 except the element corresponding to $var2$ which has the value 1)</p>

<p><strong>Gate 3</strong></p>

<p>3rd gate is the addition gate which represents $var2 + x = var3$. <strong>The vectors for addition gates are derived differently</strong>. The equation is equivalent to $(var2 + x) * 1 = var3$. So the $l$ vector represents $var2 + x$, the $r$ vector represents $1$ &amp; the $o$ vector represents $var3$</p>

<p>$l = [0, 0, 1,  0, 1, 0]$ (This represents $var2 + x$)</p>

<p>$r = [1, 0, 0, 0, 0, 0]$ (This represents $1$)</p>

<p>$o = [0, 0, 0, 0, 0, 1]$ (This represents $var3$)</p>

<p><strong>Gate 4</strong></p>

<p>Likewise, the 4th gate $var3 + 5 = out$ is equivalent to $(var3 + 5) *  1 = out$</p>

<p>$l = [5, 0, 0, 0, 0, 1]$ ($var3 + 5$)</p>

<p>$r = [1, 0, 0, 0, 0, 0]$ ($1$)</p>

<p>$o = [0, 1, 0, 0, 0, 0]$ ($out$)</p>

<p>Though we aren’t explicitly calculating &amp; showing it here, $(l\cdot S) * (r\cdot S) = (o\cdot S)$ is satisfied for Gates 2, 3 &amp; 4 also. We now have the complete R1CS with 4 constraints.</p>

<p>We can create a Matrix $L$ by using each of $l$ vectors as a row in the Matrix. Likewise Matrices $R$ &amp; $O$.</p>

<p>The Complete Satisfied R1CS is</p>

<p>\(L = 
\begin{pmatrix} 
    0&amp;0&amp;1&amp;0&amp;0&amp;0 \\
    0&amp;0&amp;0&amp;1&amp;0&amp;0 \\
    0&amp;0&amp;1&amp;0&amp;1&amp;0 \\
    5&amp;0&amp;0&amp;0&amp;0&amp;1 
\end{pmatrix}\)
\(R =
\begin{pmatrix} 
0&amp;0&amp;1&amp;0&amp;0&amp;0 \\
0&amp;0&amp;1&amp;0&amp;0&amp;0 \\
1&amp;0&amp;0&amp;0&amp;0&amp;0 \\
1&amp;0&amp;0&amp;0&amp;0&amp;0 \\
\end{pmatrix}\)
\(O = 
\begin{pmatrix} 
0&amp;0&amp;0&amp;1&amp;0&amp;0 \\
0&amp;0&amp;0&amp;0&amp;1&amp;0 \\
0&amp;0&amp;0&amp;0&amp;0&amp;1 \\
0&amp;1&amp;0&amp;0&amp;0&amp;0 \\
\end{pmatrix}\)</p>

<p>This along with our solution vector $S = [1, out, x, var1, var2, var3]$ forms our R1CS.</p>

<p>Let’s define these matrices in sage. I have shown only 1 below, but the remaining 2 will also be defined similarly.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">p</span> <span class="o">=</span> <span class="mi">641</span>
<span class="no">Fp</span> <span class="o">=</span> <span class="no">GF</span><span class="p">(</span><span class="nb">p</span><span class="p">)</span>
<span class="no">Rng</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">Fp</span><span class="p">)</span>

<span class="no">L</span> <span class="o">=</span> <span class="no">Matrix</span><span class="p">(</span><span class="no">Fp</span><span class="p">,</span> <span class="p">[</span>
    <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">],</span>
    <span class="p">[</span><span class="mi">5</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">]]</span>
    <span class="p">)</span>

</code></pre></div></div>

<h2 id="qap">QAP</h2>

<p>The next step is taking this R1CS and converting it into the QAP form, which implements the exact same logic except using polynomials. In the construction used, the number of polynomials &amp; their degree would depend on the length of the solution vector &amp; the number of gates. The solution vector contains 6 elements, so we can construct 6 polynomials. Each gate contributes 1 point to each polynomial. We have 4 gates here, we get 4 points per polynomial. 4 points allows us to define a polynomial of maximum degree 3. So we can construct 6 polynomials each with a maximum degree of 3. So we can transform our matrices collectively into 6 polynomials, each of degree 3.</p>

<p>A polynomial of degree $n$ is defined by a minimum of $n+1$ points. Each column of $L$, $R$ &amp; $O$ has 4 elements. So each such column can be converted to a polynomial of degree 3. We use Lagrange’s Polynomial Interpolation to do this.</p>

<p>For e.g. 1st column of $L$ is $[0, 0, 0, 5]^T$ (shown transposed). We can consider each element as the y-coordinate corresponding to $x \in [1, 2, 3, 4]$. So we get $4$ sets of points - $(1,0), (2,0), (3,0), (4,5)$. This is an arbitrary interpretation which we use to convert the R1CS into the QAP form. We could have just as well used $[5, 7, 9, 11]$ instead of $[1, 2, 3, 4]$ as long as we are consistent across all equations..</p>

<p>We can find the polynomial passing through these 4 points using <a href="https://en.wikipedia.org/wiki/Lagrange_polynomial">Lagrange Interpolation</a>.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rng</span><span class="p">.</span><span class="nf">&lt;</span><span class="n">x</span><span class="o">&gt;</span> <span class="o">=</span> <span class="no">PolynomialRing</span><span class="p">(</span><span class="no">Fp</span><span class="p">)</span> <span class="c1"># Polynomial Ring in GF(641)</span>
<span class="n">points</span> <span class="o">=</span> <span class="p">[(</span><span class="mi">1</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="mi">0</span><span class="p">),</span> <span class="p">(</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">)]</span>
<span class="no">Rng</span><span class="p">.</span><span class="nf">lagrange_polynomial</span><span class="p">(</span><span class="n">points</span><span class="p">)</span>
<span class="mi">535</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">636</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">116</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">636</span>
</code></pre></div></div>

<p>So the polynomial corresponding to the first Column of $L$ is</p>

<p>$535x^3 + 636x^2 + 116x + 636$</p>

<p>Since we have $18$ polynomials to interpolate, we can do it in loops in sage. And after calling <code class="language-plaintext highlighter-rouge">Rng.lagrange_polynomial(points)</code>, we call the coefficients method on the output polynomial (i.e. <code class="language-plaintext highlighter-rouge">Rng.lagrange_polynomial(points).coefficients(sparse=False)</code>) which transforms  the coefficients of each output polynomial into a list which we then collect in a Matrix.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">M</span> <span class="o">=</span> <span class="p">[</span><span class="no">L</span><span class="p">,</span> <span class="no">R</span><span class="p">,</span> <span class="no">O</span><span class="p">]</span>
<span class="no">PolyM</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">for</span> <span class="n">m</span> <span class="k">in</span> <span class="no">M</span><span class="p">:</span>
    <span class="no">PolyList</span> <span class="o">=</span> <span class="p">[]</span>
    <span class="k">for</span> <span class="n">i</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="nf">ncols</span><span class="p">()):</span>
        <span class="n">points</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">for</span> <span class="n">j</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="nf">nrows</span><span class="p">()):</span>
            <span class="n">points</span><span class="p">.</span><span class="nf">append</span><span class="p">([</span><span class="n">j</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="n">m</span><span class="p">[</span><span class="n">j</span><span class="p">,</span><span class="n">i</span><span class="p">]])</span>
        <span class="no">Poly</span> <span class="o">=</span> <span class="no">Rng</span><span class="p">.</span><span class="nf">lagrange_polynomial</span><span class="p">(</span><span class="n">points</span><span class="p">).</span><span class="nf">coefficients</span><span class="p">(</span><span class="n">sparse</span><span class="o">=</span><span class="no">False</span><span class="p">)</span>
        <span class="k">if</span><span class="p">(</span><span class="n">len</span><span class="p">(</span><span class="no">Poly</span><span class="p">)</span> <span class="o">&lt;</span> <span class="n">m</span><span class="p">.</span><span class="nf">nrows</span><span class="p">()):</span>
            <span class="c1"># if degree of the polynomial is less than 4</span>
            <span class="c1"># we add zeroes to represent the missed out terms</span>
            <span class="n">dif</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="nf">nrows</span><span class="p">()</span> <span class="o">-</span> <span class="n">len</span><span class="p">(</span><span class="no">Poly</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">c</span> <span class="k">in</span> <span class="n">range</span><span class="p">(</span><span class="n">dif</span><span class="p">):</span>
                <span class="no">Poly</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
        <span class="no">PolyList</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Poly</span><span class="p">)</span>
    <span class="no">PolyM</span><span class="p">.</span><span class="nf">append</span><span class="p">(</span><span class="no">Matrix</span><span class="p">(</span><span class="no">Fp</span><span class="p">,</span> <span class="no">PolyList</span><span class="p">))</span>
</code></pre></div></div>

<p>If we print out the 3 matrices holding 6 polynomials each we get</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># PolyM[0] = Lm (Matrix of L Polynomials) </span>
<span class="p">[</span><span class="mi">636</span> <span class="mi">116</span> <span class="mi">636</span> <span class="mi">535</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">8</span> <span class="mi">416</span>   <span class="mi">5</span> <span class="mi">213</span><span class="p">]</span>
<span class="p">[</span><span class="mi">635</span> <span class="mi">330</span> <span class="mi">637</span> <span class="mi">321</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">4</span> <span class="mi">634</span> <span class="mi">324</span> <span class="mi">320</span><span class="p">]</span>
<span class="p">[</span><span class="mi">640</span> <span class="mi">536</span> <span class="mi">640</span> <span class="mi">107</span><span class="p">]</span>

<span class="c1"># PolyM[1] = Rm (Matrix of R Polynomials)</span>
<span class="p">[</span>  <span class="mi">3</span> <span class="mi">529</span> <span class="mi">323</span> <span class="mi">427</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span><span class="mi">639</span> <span class="mi">112</span> <span class="mi">318</span> <span class="mi">214</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>

<span class="c1"># PolyM[2] = Om (Matrix of O Polynomials)</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span><span class="mi">640</span> <span class="mi">536</span> <span class="mi">640</span> <span class="mi">107</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span>   <span class="mi">0</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">4</span> <span class="mi">423</span> <span class="mi">322</span> <span class="mi">534</span><span class="p">]</span>
<span class="p">[</span><span class="mi">635</span> <span class="mi">330</span> <span class="mi">637</span> <span class="mi">321</span><span class="p">]</span>
<span class="p">[</span>  <span class="mi">4</span> <span class="mi">634</span> <span class="mi">324</span> <span class="mi">320</span><span class="p">]</span>
</code></pre></div></div>
<p>For convenience, we will refer to $PolyM[0]$, $PolyM[1]$ &amp; $PolyM[2]$ as $Lm$,$Rm$ &amp; $Om$</p>

<p>You can see the polynomial we got from the first column of $L$ (i.e $535x^3 + 636x^2 + 116x + 636$) appear in first row here of the Matrix $Lm$ . The Row is to be interpreted in reverse order - i.e $[636\ 116\ 636\ 535]$ is $535x^3 + 636x^2 + 116x + 636$</p>

<p>This finishes the transformation of the problem to the QAP Form. What do we achieve by converting it into the QAP form? Instead of checking the constraints in the R1CS individually, we can now check all of the constraints at the same time by doing the dot product check on the polynomials.</p>

<p>Let’s take a closer look at $Lm$
\(\begin{pmatrix}
636&amp;116&amp;636&amp;535 \\
0&amp;0&amp;0&amp;0 \\
8&amp;416&amp;5&amp;213 \\
635&amp;330&amp;637&amp;321 \\
4&amp;634&amp;324&amp;320 \\
640&amp;536&amp;640&amp;107
\end{pmatrix}\)</p>

<p>This has 6 left polynomials, one in each row.</p>

<p>Our solution vector $S = [1, out, x, var1, var2, var3]$ also has 6 elements. So we can do a dot product of $S\cdot Lm$ whose output again will be a polynomial. Likewise for the other 2 polynomial matrices.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># We define the solution vector also in the field</span>
<span class="no">S</span> <span class="o">=</span> <span class="n">vector</span><span class="p">(</span><span class="no">Fp</span><span class="p">,[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">35</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">9</span><span class="p">,</span> <span class="mi">27</span><span class="p">,</span> <span class="mi">30</span><span class="p">])</span>

<span class="c1"># Create the Lx, Rx &amp; Ox polynomial</span>
<span class="c1"># In the program, we use Fx to denote F(x)</span>
<span class="no">Lx</span> <span class="o">=</span> <span class="no">Rng</span><span class="p">(</span><span class="n">list</span><span class="p">(</span><span class="no">S</span><span class="o">*</span><span class="no">PolyM</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
<span class="no">Rx</span> <span class="o">=</span> <span class="no">Rng</span><span class="p">(</span><span class="n">list</span><span class="p">(</span><span class="no">S</span><span class="o">*</span><span class="no">PolyM</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span>
<span class="no">Ox</span> <span class="o">=</span> <span class="no">Rng</span><span class="p">(</span><span class="n">list</span><span class="p">(</span><span class="no">S</span><span class="o">*</span><span class="no">PolyM</span><span class="p">[</span><span class="mi">2</span><span class="p">]))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Lx = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">Lx</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Rx = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">Rx</span><span class="p">))</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Ox = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">Ox</span><span class="p">))</span>

<span class="no">Lx</span> <span class="o">=</span> <span class="mi">529</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">359</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">354</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">43</span>
<span class="no">Rx</span> <span class="o">=</span> <span class="mi">428</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">636</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">224</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">638</span>
<span class="no">Ox</span> <span class="o">=</span> <span class="mi">537</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">296</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">499</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">600</span>

</code></pre></div></div>

<p>So by taking a dot product of $S$ with each of $Lm$, $Rm$ and $Om$, we created 3 polynomials $L(x)$, $R(x)$ and $O(x)$</p>

<p>We can define a new polynomial $T(x) = L(x) *  R(x) - O(x)$.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">....</span><span class="p">:</span> <span class="c1"># New Polynomial T</span>
<span class="o">....</span><span class="p">:</span> <span class="no">T</span> <span class="o">=</span> <span class="no">Lx</span><span class="o">*</span><span class="no">Rx</span> <span class="o">-</span> <span class="no">Ox</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"T(x) = "</span><span class="p">,</span> <span class="k">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="no">T</span><span class="p">)</span>
<span class="no">T</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="no">T</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">=</span> <span class="mi">139</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">6</span> <span class="o">+</span> <span class="mi">372</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">5</span> <span class="o">+</span> <span class="mi">275</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">4</span> <span class="o">+</span> <span class="mi">58</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">3</span> <span class="o">+</span> <span class="mi">147</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">379</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">553</span>

</code></pre></div></div>

<p>In the R1CS, we had checked if $(l\cdot S) * (r\cdot S) = (o\cdot S)$ for each of the Gates.
After conversion to QAP, we can do the same by checking the value of $T$ at $x$ at $1, 2, 3, 4$ - if all 4 are zero, then we have checked all the constraints together - thereby proving that the solution vector known to the Provers satisfies the equation.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">....</span><span class="p">:</span> <span class="c1">#Let's check Tx at x = 1, 2, 3, 4</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"T(1) = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">T</span><span class="p">(</span><span class="mi">1</span><span class="p">)))</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"T(2) = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">T</span><span class="p">(</span><span class="mi">2</span><span class="p">)))</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"T(3) = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">T</span><span class="p">(</span><span class="mi">3</span><span class="p">)))</span>
<span class="o">....</span><span class="p">:</span> <span class="nb">print</span><span class="p">(</span><span class="s2">"T(4) = "</span> <span class="o">+</span> <span class="n">str</span><span class="p">(</span><span class="no">T</span><span class="p">(</span><span class="mi">4</span><span class="p">)))</span>
<span class="o">....</span><span class="p">:</span>
<span class="no">T</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="no">T</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="no">T</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
<span class="no">T</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></div>

<p>However, the Verifier doesn’t know the polynomial $T$, nor can he compute it since he doesn’t know the solution vector. So the Prover has to prove it to the Verifier that $T$ is zero at $x=1, x=2, x=3,x=4$. 
If $T$ is zero at $x=1, x=2, x=3,x=4$, then it means these are all roots of $T$. So we create a new polynomial $Z$ known by both the Prover &amp; the Verifier.</p>

<p>$Z(x) = (x-1)(x-2)(x-3)(x-4)$</p>

<p>If $T$ is divided by $Z$, then it will be perfectly divisible &amp; will leave no remainder i.e. there must exist a Polynomial $H$ such that $T(x) = H(x) \cdot Z(x)$</p>

<p>Let’s check this out in sagemath</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Z</span> <span class="o">=</span> <span class="no">Rng</span><span class="p">((</span><span class="n">x</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="mi">2</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="mi">3</span><span class="p">)</span><span class="o">*</span><span class="p">(</span><span class="n">x</span><span class="o">-</span><span class="mi">4</span><span class="p">))</span>
<span class="no">H</span> <span class="o">=</span> <span class="no">T</span><span class="p">.</span><span class="nf">quo_rem</span><span class="p">(</span><span class="no">Z</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Quotient of T/Z = "</span><span class="p">,</span> <span class="k">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="no">H</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">"Remainder of T/Z = "</span><span class="p">,</span> <span class="k">end</span><span class="o">=</span><span class="s2">""</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="no">H</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>

<span class="no">Quotient</span> <span class="n">of</span> <span class="no">Z</span><span class="o">/</span><span class="no">T</span> <span class="o">=</span> <span class="mi">139</span><span class="o">*</span><span class="n">x</span><span class="o">^</span><span class="mi">2</span> <span class="o">+</span> <span class="mi">480</span><span class="o">*</span><span class="n">x</span> <span class="o">+</span> <span class="mi">210</span>
<span class="no">Remainder</span> <span class="n">of</span> <span class="no">Z</span><span class="o">/</span><span class="no">T</span> <span class="o">=</span> <span class="mi">0</span>
</code></pre></div></div>

<p>The reason we get a $0$ remainder is because $Z$ divides $T$. If you change even a single element in the solution vector, then $T$ will no longer divide $Z$ exactly &amp; you will end up with a remainder.</p>

<p>In a typical <strong>zkSNARK</strong>, the prover proves that $Z$ exactly divides $T$ using Polynomial Commitments &amp; Elliptic Curve Bilinear Pairings. You can take a look at my <a href="/Groth16">Groth16</a> post to check how it’s done in Groth16.</p>

<p><strong>Note:</strong> An older version of this post used $\mathbb F_{41}$, it’s been updated to use $\mathbb F_{641}$ now.</p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FR1CSQAP%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">The KZG/Kate Polynomial Commitment Scheme</title><link href="https://risencrypto.github.io/Kate/" rel="alternate" type="text/html" title="The KZG/Kate Polynomial Commitment Scheme" /><published>2023-01-24T00:00:00+00:00</published><updated>2023-01-24T00:00:00+00:00</updated><id>https://risencrypto.github.io/Kate</id><content type="html" xml:base="https://risencrypto.github.io/Kate/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<h3 id="introduction">Introduction</h3>

<p>Commitment schemes are fundamental components of many cryptographic protocols. A secure commitment scheme allows a committer to publish a value, called the commitment, which binds her to a message (binding) without revealing it (hiding). Later, she may open the commitment and reveal the committed message to a verifier, who can check that the message is consistent with the commitment.</p>

<p>Consider the following scenario.</p>

<ul>
  <li>
    <p>Peggy wants to commit to a message $m$. To do so, she writes down $m$ on a piece of paper, puts it in a box, and locks it using a padlock.</p>
  </li>
  <li>
    <p>Peggy gives the box to Victor.</p>
  </li>
  <li>
    <p>If Peggy wants to, she can later open the commitment by giving Victor the key to the padlock.</p>
  </li>
</ul>

<p>There are two basic properties here, which are essential to any commitment scheme:</p>

<ul>
  <li>
    <p>Having given away the box, Peggy cannot anymore change what is inside. Hence, when the box is opened, we know that what is revealed really was the choice that Peggy committed to originally. This is called
the <strong>Binding</strong> property.</p>
  </li>
  <li>
    <p>When Victor receives the box, he cannot tell what is inside before Peggy decides to give him the key. This is called the <strong>Hiding</strong> property.</p>
  </li>
</ul>

<p>Polynomials are frequently used in cryptography because they can be used to encode a lot of information. A Polynomial Commitment Scheme (PCS) allows the committer to commit to a polynomial with a commitment string that can be used by a verifier to confirm claimed evaluations of the committed polynomial. We will look at one such PCS called KZG (Kate, Zaverucha, Goldberg). It’s also referred to as the Kate Commitment Scheme.</p>

<p><em>Pre-requisite topic before we discuss the KZG PCS</em></p>

<h4 id="elliptic-curve-pairings">Elliptic Curve Pairings</h4>

<p>An Elliptic Curve Pairing is defined as a map</p>

<p>$e : \mathbb G_1 \times \mathbb G_2 \mapsto \mathbb G_T$</p>

<p>$\mathbb G_1$ can be equal to $\mathbb G_2$ i.e. $\mathbb G_1 = \mathbb G_2 = \mathbb G$. Such a pairing is called as a Symmetric Pairing. If they are not equal, then it’s called as an Asymmetric Pairing.</p>

<p>Let $G_1$ &amp; $G_2$ be generators of $\mathbb G_1$ &amp; $\mathbb G_2$ respectively. Let $a$ &amp; $b$ be scalars.
The core property of Elliptic Curve Pairings which we use the most is the following.</p>

<p>$e(a G_1, b G_2) = e(b G_1, a G_2) = e(ab G_1, G_2) = e(G_1, ab G_2) = e(G_1, a G_2)^{b} = e(G_1, G_2)^{ab}$</p>

<p>If you are not familiar with pairings, I have given a small introduction to Pairings as part of this post - <a href="https://risencrypto.github.io/WeilMOV/">Weil Pairing and the MOV attack</a>.</p>

<h4 id="the-schwartz-zippel-lemma">The Schwartz-Zippel Lemma</h4>

<p>Let $f$ be a polynomial from $\mathbb F_p[x]$ of degree less than or equal to $d$. Let $p \approx 2^{256}$ &amp; $d \le 2^{40}$. If we test $f$ at a random value $r \in \mathbb F_p$, then the probability that $f(r) = 0$ would be $\frac {d}{p}$ which for these values of $d$ &amp; $p$ would be very, very small. So, if $f(r) = 0$, then with high probability, $f$ is a zero polynomial (i.e., zero at all points). This is a simple test to check if a committed polynomial is a zero polynomial. Open the commitment to the polynomial at a random point &amp; if it opens to zero, then it is a zero polynomial.</p>

<p>This also helps to prove that 2 polynomials are equal. If the 2 polynomials are $f$ &amp; $g$, we create a new polynomial $p(x) = f(x)\space - \space g(x)$.</p>

<p>If we test $p$ at a random $r \in \mathbb F_p$ &amp; $f(r)$ turns out to be $0$, then $p$ is a zero polynomial with very high probability. If $p$ is a zero polynomial, then it obviously means $f = g$.</p>

<p>The Commitment Scheme tests the polynomials only at a small number of points ($a$ &amp; the opening point). The Binding property of the commitment scheme is based on the Schwartz-Zippel Lemma.</p>

<h3 id="the-commitment-scheme">The Commitment Scheme</h3>

<p>Let $F(x)\in \mathbb F_p[x]$ be the polynomial which needs to be committed. $F(x)$ is a polynomial of degree $d$ or less.</p>

<p>We will first describe the commitment using Symmetric Elliptic Curve Pairing - i.e. $e : \mathbb G \times \mathbb G \mapsto \mathbb G_T$. $\mathbb G$ is an Elliptic Curve group of order $p$ with a generator $G$.</p>

<h4 id="trusted-setup">Trusted Setup</h4>

<p>The first stage of the commitment scheme is a trusted setup. During the trusted setup, a random value $a \in \mathbb F_p$ is sampled. Then the following tuple of size $d+1$ known as the Reference String is generated - $\lbrace G, aG,a^2G, a^3G, …, a^dG \rbrace$. After generating the tuple, the random value $a$ is destroyed such that it’s not known to anyone including the Prover or the Verifier. The destroyed value is called as <strong>toxic waste</strong>. If toxic waste is known to anyone, they can use it to generate fraud proofs.</p>

<p><strong>Commitment</strong></p>

<p>Let’s denote the commitment of the polynomial $F(x)$ as $C_F$ where</p>

<p>$C_F = F(a)\cdot G$ where $F(a)$ is the polynomial evaluated at $x=a$.</p>

<p>Though $a$ has been deleted, the committer can stil compute the commitment using the Reference String.</p>

<p>Let $F(x) = f_0 + f_1x + f_2x^2 + … + f_dx^d$</p>

<p>$F(a) = f_0 + f_1a + f_2a^2 + … + f_da^d$</p>

<p>So $C_F = F(a)\cdot G = (f_0 + f_1a + f_2a^2 + … + f_da^d)\cdot G$</p>

<p>$C_F = f_0\cdot G + f_1a\cdot G + f_2a^2\cdot G + … + f_da^d\cdot G$</p>

<p>Though the committer doesn’t know $a$, she knows $\lbrace G, aG,a^2G, a^3G, …, a^dG \rbrace$ from the reference string &amp; can evaluate $C_F$ &amp; evaluate the commitment. The committer sends the commitment to the verifier.</p>

<p>Since $G$ is a generator of the Elliptic Curve group $\mathbb G$, the commitment is a point on the Elliptic Curve.</p>

<p>The <strong>Hiding</strong> property of the commitment is based on the <strong>Discrete Logarithm</strong> problem being hard in $\mathbb G$</p>

<p><strong>Full Open &amp; Verify</strong></p>

<p>In a full open, the committer sends the polynomial to the verifier &amp; the verifier can use the reference string &amp; compute the commitment himself &amp; verify if it matches with the commitment sent originally by the committer.</p>

<p><strong>Partial Open or Evaluation Proof</strong></p>

<p>In KZG, committer can also do a partial open (i.e. evaluation at a single value) which is called as the Evaluation Proof.</p>

<p>The verifier sends a value $b$ randomly selected from $\mathbb F_p$ to the committer. The committer evaluates the polynomial $F(x)$ at $x=b$ as $F(b) = c$ &amp; sends $c$ to the verifier. The committer also has to provide a proof to the verifier that $F(b) = c$.</p>

<p>The proof which the committer provides to the verifier is the commitment of the Quotient Polynomial $Q(x)$ i.e. $C_Q$</p>

<p>$Q(x)$ is defined as</p>

<p>$Q(x) = \frac {F(x) - F(b)} {x-b} = \frac {F(x) - c} {x-b}$</p>

<p>As per <strong>Little Bezout’s Theorem</strong>, if $F(x)$ is a polynomial, then $F(x) - F(b)$ is perfectly divisible by $(x-b)$ i.e. the remainder is $0$. So $Q(x)$ above is a polynomial i.e. it won’t have any variable in the denominator or any negative exponents. Since $Q(x)$ is a polynomial, then the committer can calculate the commitment of $Q(x)$ using the Reference String as</p>

<p>$C_Q = Q(a)\cdot G$</p>

<p>If $F(x)$ weren’t perfectly divisible by $(x-b)$, then $Q(x)$ would have a denominator &amp; negative exponents &amp; the commiter wouldn’t be able to evaluate it using just the Reference String &amp; without knowing $a$.</p>

<p>The committer sends $C_Q$ to the verifier as the Evaluation Proof.</p>

<p><strong>Verifying</strong></p>

<p>A commitment scheme is said to be <strong>complete</strong> if anything which is true is provable. It is said to be <strong>sound</strong> if everything which is provable is true - i.e. anything which is false cannot be proven by the scheme.</p>

<p>The verifier has $C_F$, $C_Q$ &amp; $c$. He needs to verify that $F(b) = c$</p>

<p>$Q(x) = \frac {F(x) - c} {x-b}$</p>

<p>So,</p>

<p>$(x-b)\cdot Q(x) = F(x) - c$</p>

<p>If you evaluate this at $x = a$, it becomes</p>

<p>$(a-b)\cdot Q(a) = F(a) - c$</p>

<p>Multiplying both sides by the generator $G$, we get</p>

<p>$(a-b)\cdot Q(a)\cdot G = F(a)\cdot G - c\cdot G$</p>

<p>Now, $C_Q = Q(a)\cdot G$ &amp; $C_F = F(a)\cdot G$. So substituting, we get</p>

<p>$(a-b)\cdot C_Q = C_F - c\cdot G$</p>

<p>If the verifier is able to verify that the above equality holds good, then he has verified the commitment. But since the verifier doesn’t know the value of $a$, he cannot directly verify if this equality holds good.</p>

<p>However, the verifier can use Elliptic Curve Pairings to verify whether the above equality holds even without knowing $a$. 
The pairing is denoted by the map</p>

<p>$e:\space \mathbb G$ X $\mathbb G  \mapsto \mathbb G_T$</p>

<p>This is the equality to check</p>

<p>$(a-b)\cdot C_Q \stackrel {?}{=} C_F - c\cdot G$</p>

<p>Each input to the pairing map needs to be an element of the Group. Any commitment is a scalar multiple of the generator of the group, so both $C_F$ &amp; $C_Q$ are elements of $\mathbb G$. Since $C_Q$ is an element of the group, multiplying it with the scalar $a-b$ also will result in an  element of the group. So $(a-b)\cdot C_Q$ is also an element of $\mathbb G$. $C_F$ &amp; $c\cdot G$ are both elements of the group, so $C_F - c\cdot G$ is also an element of the group. So all the terms in the equality are group elements. So they can be inputs to the pairing map.</p>

<p>By passing the sides of the equality as the first parameter to the map &amp; pass $G$ as the 2nd param for each side, we can turn the equality to be verified into</p>

<p>$e((a-b)\cdot C_Q, G) \stackrel {?}{=} e(C_F - c\cdot G, G)$</p>

<p>This still doesn’t help us because we don’t know $a$.</p>

<p>However, bilinearity property of the pairing map means that</p>

<p>$e(\alpha A,B) = e(A, \alpha B)$ if $\alpha$ is a scalar.</p>

<p>So we can rewrite it as</p>

<p>$e(C_Q, (a-b)\cdot G) \stackrel {?}{=} e(C_F - c\cdot G, G)$</p>

<p>Further simplifying</p>

<p>$e(C_Q, aG - bG) \stackrel {?}{=} e(C_F - cG, G)$</p>

<p>Though we don’t know $a$, we do know $aG$ from our Reference String. So now the verifier can check whether the above equality is true or not. This ends the proof.</p>

<p>Note that any pairing based equality check $e(A, B) \stackrel {?}{=} e(P,Q)$ can also be expressed in a diff way.</p>

<p>$e(A, B) \stackrel {?}{=} e(P,Q)$</p>

<p>$e(A, B) \stackrel {?}{=} e((-1)\cdot (-P),Q)$</p>

<p>Again using the bilinearly property on the Right hand side, we get</p>

<p>$e(A, B) \stackrel {?}{=} e(-P,Q)^{-1}$</p>

<p>which is the same as</p>

<p>$e(A, B)\cdot e(-P,Q) \stackrel {?}{=} 1$</p>

<p>Many texts &amp; papers represent pairing based checks in the above way.</p>

<h3 id="asymmetric-pairings">Asymmetric Pairings</h3>
<p>Above, we used a symmetric pairing to prove the correctness of the above verification equation. However, an Asymmetric Pairing (i.e. $\mathbb G_1 \ne \mathbb G_2$) can also be used &amp; is usually preferred. The proof for the verify equation using Asymmetric Pairings is very similar &amp; given below.</p>

<p>Let’s start from this point in the earlier proof.</p>

<p>$(a-b)\cdot Q(a) \stackrel {?}{=} F(a) - c$</p>

<p>Multiplying both sides by $G_1$</p>

<p>$(a-b)\cdot Q(a)\cdot G_1 \stackrel {?}{=} F(a) \cdot G_1 - c \cdot G_1$</p>

<p>$(a-b)\cdot C_Q \stackrel {?}{=} C_F - c \cdot G_1$</p>

<p>Using pairings,</p>

<p>$e((a-b)\cdot C_Q,G_2) \stackrel {?}{=} e(C_F - c \cdot G_1, G_2)$</p>

<p>Using the bilinear property,</p>

<p>$e(C_Q,(a-b)\cdot G_2) \stackrel {?}{=} e(C_F - c \cdot G_1, G_2)$</p>

<p>$e(C_Q,a\cdot G_2 - b\cdot G_2) \stackrel {?}{=} e(C_F - c \cdot G_1, G_2)$</p>

<p>Everything except $a\cdot G_2$ is either calculated or found in the SRS for $G_1$. And $a\cdot G_2$ will be part of the SRS for $G_2$ &amp; that is also known and thus the equality can be verified.</p>

<h3 id="batch-mode">Batch Mode</h3>

<h4 id="batch-mode-single-polynomial-multiple-points">Batch Mode Single Polynomial, multiple points</h4>

<p>KZG commitments can also be opened &amp; verified at multiple points using a single proof.</p>

<p>In the stand-alone opening, the committer evaluated $F(x)$ at $b \in \mathbb F_p$ as $F(b) = c$ &amp; provided $c$ along with the proof to the verifier.</p>

<p>In batch mode, the verifier sends to the committer a set of values $ B = \lbrace b_1, b_2, b_3, …, b_t \rbrace$ such that $t \lt d$, the committer evaluates $f(b_1) = c_1, f(b_2) = c_2, …, f(b_t) = c_t$ and constructs the set $C = \lbrace c_1, c_2, c_3, …, c_t \rbrace$.</p>

<p>Let $P(x) = (x-b_1)(x-b_2)…(x-b_t)$</p>

<p>Since the degree of $F(x)$ is $d$ &amp; $t \lt d$, we can divide $F(x)$ by $P(x)$. Let the quotient of the division be $Q(x)$ &amp; the remainder be $R(x)$ (Note that we aren’t saying here that $F(x)$ is divisible by $Q(x)$, so we have remainder here).</p>

<p>i.e. $F(x) = P(x) Q(x) + R(x)$</p>

<p>The committer computes $Q(x)$ &amp; also the commitment for $Q(x)$ i.e. $C_Q$ &amp; sends those also to the verifier along with the set $C$</p>

<p>The committer can also send $R(x)$ to the verifier. Alternately, the verifier can also find the polynomial $R(x)$ himself as shown below.</p>

<p>$F(x) = P(x) Q(x) + R(x)$ with $P(x) = (x-b_1)(x-b_2)…(x-b_t)$</p>

<p>For any $b_i \in B = \lbrace b_1, b_2, b_3, …, b_t \rbrace$, it’s pretty apparent that $P(x)$ is zero. &amp; hence the middle term vanishes at all $b_i \in B$.</p>

<p>So for all $b_i \in B$, $F(x) = R(x)$</p>

<p>Since $F(b_i) = c_i$ for all $\lbrace b_i \in B, c_i \in C \rbrace$, likewise</p>

<p>$R(b_i) = c_i$ for all $\lbrace b_i \in B, c_i \in C \rbrace$</p>

<p>Since the degree of $Q(x)$ is $t$ &amp; $R(x)$ is the remainder of dividing $F(x)$ by $Q(x)$, the degree of $R(x)$ is less than $t$. Since the verifier knows evaluation of $R(x)$ at $t$ points, he can find $R(x)$ using Lagrange’s Interpolation. So now $R(x)$ is known to the verifier.</p>

<p>The Verifier can also find the polynomial $P(x)$ which is</p>

<p>$P(x) = (x-b_1)(x-b_2)…(x-b_t)$</p>

<p>The Verifier also computes the commitments of $P(x)$ &amp; $R(x)$</p>

<p>$C_P = P(a)\cdot G$</p>

<p>$C_R = R(a)\cdot G$</p>

<p>Now the verifier can verify the Batch Evaluation by doing the following steps.</p>

<p><strong>1)</strong> Verifier checks if $F(b_i) \stackrel {?}{=} R(b_i)$ for all $b_i \in B$. The committer has provided the set $C$ which are the evaluations of $F(x)$ at all $b_i \in B$. And the verifier knows $R(x)$, so he can also evaluate $R(x)$ at all the $b_i \in B$. So he can verify if $F(b_i) \stackrel {?}{=} R(b_i)$ for all $b_i \in B$</p>

<p><strong>2)</strong> The verifier has to verify that the following equality holds</p>

<p>$F(x) \stackrel {?}{=} P(x) Q(x) + R(x)$</p>

<p>$F(x) - R(x) \stackrel {?}{=} P(x) Q(x)$</p>

<p>Multiply both sides by the generator $G$</p>

<p>$F(x)\cdot G - R(x)\cdot G \stackrel {?}{=} P(x) Q(x)\cdot G$</p>

<p>Evaluate the above at $a$</p>

<p>$F(a)\cdot G - R(a)\cdot G \stackrel {?}{=} P(a) Q(a)\cdot G$.</p>

<p>$F(a)\cdot G$ is the committment of $F$ i.e. $C_F$. Likewise, 2 other terms above are also committments. So,</p>

<p>$C_F - C_R \stackrel {?}{=} P(a)\cdot C_Q$</p>

<p>The verifier needs to evaluate the above to verify the proof. However, since $a$ is unknown, he cannot evaluate $P(a)$. But like before, he can use pairings.</p>

<p>$C_F$ &amp; $C_R$ are both elements of $\mathbb G$, so $C_F - C_R$ is also an element of $\mathbb G$</p>

<p>$C_Q$ is an element of $\mathbb G$ &amp; $P(a)$ is a scalar. So $P(a)\cdot C_Q$ is also an element of $\mathbb G$.</p>

<p>So we can apply the pairing map to both sides</p>

<p>$e(C_F - C_R, G) \stackrel {?}{=} e(P(a)\cdot C_Q, G)$</p>

<p>Note that $P(a)$ is a scalar here.And the bilinearity property of the pairing map means that</p>

<p>$e(\alpha A,B) = e(A, \alpha B)$ where $\alpha$ is a scalar.</p>

<p>So, we can rewrite the Right Hand Side as</p>

<p>$e(C_F - C_R, G) \stackrel {?}{=} e(C_Q, P(a)\cdot G)$</p>

<p>$C_P= P(a).G$, so</p>

<p>$e(C_F - C_R, G) \stackrel {?}{=} e(C_Q, C_P)$</p>

<p>The verifier knows all the terms of this pairing &amp; can evaluate to the check if the equality holds or not.</p>

<h4 id="batch-mode-multiple-polynomials-same-point">Batch Mode Multiple Polynomials, same point</h4>
<hr />
<p><strong>Note:</strong> The KZG paper covers standalone openings &amp; batch opening of a single polynomial at multiple points.</p>

<p>However, there are also protocols for batch opening of  multiple polynomials at the same point &amp; batch opening of multiple polynomials at multiple points. Both are covered in the PLONK paper. These protocols are described below.</p>

<hr />

<p>Consider $f_1, f_2,…, f_t \in \mathbb F_p[x]$ with $t &lt; d$ &amp; $z\in \mathbb F_p$. Let $C_{f_1},C_{f_2}, …, C_{f_t}$ be the commitments to these polynomials.</p>

<p>The openings $f_1(z)=s_1, f_2(z) = s_2, … ,f_t(z)= s_t$ have to be verified.</p>

<ul>
  <li>
    <p>Verifier sends random $\gamma \in \mathbb F_p$ to Prover</p>
  </li>
  <li>
    <p>Prover computes the polynomial</p>
  </li>
</ul>

<p>$\qquad h(x) = \sum_{i=1}^t \gamma^{i-1} \cdot \frac {f_i(x) - f_i(z)}{x-z}$</p>

<ul>
  <li>Prover computes &amp; sends $C_h$, the commitment for $h(x)$ to the verifier.</li>
</ul>

<p>Now,</p>

<p>$f_i(z) = s_i$</p>

<p>Verifier has to check if</p>

<p>$h(x) \stackrel {?}{=} \sum_{i=1}^t \gamma^{i-1} \cdot \frac {f_i(x) - s_i}{x-z}$</p>

<p>$h(x)(x-z) \stackrel {?}{=} \sum_{i=1}^t \gamma^{i-1} \cdot (f_i(x) - s_i)$</p>

<p>$h(x)(x-z) \stackrel {?}{=} \sum_{i=1}^t \gamma^{i-1} \cdot f_i(x) - \sum_{i=1}^t \gamma^{i-1} \cdot s_i$</p>

<p>Multiplying both sides by G &amp; evaluating at $x=a$</p>

<p>$h(a)\cdot G \cdot (a-z) \stackrel {?}{=} \sum_{i=1}^t \gamma^{i-1} \cdot f_i(a)\cdot G - \sum_{i=1}^t \gamma^{i-1} \cdot s_i\cdot G $</p>

<p>$C_h = h(a)\cdot G$</p>

<p>$C_{f_i} = f_i(a)\cdot G$</p>

<p>$C_h \cdot (a-z) \stackrel {?}{=} \sum_{i=1}^t \gamma^{i-1} \cdot C_{f_i} - \sum_{i=1}^t \gamma^{i-1} \cdot s_i\cdot G \quad — (Eq\space\space 1)$</p>

<p>Let $F = \sum_{i=1}^t \gamma^{i-1} \cdot C_{f_i}$</p>

<p>Let $v = \sum_{i=1}^t \gamma^{i-1} \cdot s_i\cdot G$</p>

<p>Substituting the above in $(Eq\space\space 1)$</p>

<p>$C_f \cdot (a-z) \stackrel {?}{=} F - v \quad — (Eq\space\space 2)$</p>

<p>Using pairings,</p>

<p>$e(C_f \cdot (a-z), G) \stackrel {?}{=} e(F - v, G)$</p>

<p>Using the bilinearity property,</p>

<p>$e(C_f, (a-z)\cdot G) \stackrel {?}{=} e(F - v, G)$</p>

<p>$e(C_f, aG - zG) \stackrel {?}{=} e(F - v, G)$</p>

<p>$z$ is known, so $zG$ is known. $aG$ is known from the SRS. $F$ &amp; $v$ are also computable. So all the terms in the above are known &amp; the verifier can check if the equality holds or not.</p>

<h4 id="batch-mode-multiple-polynomials-multiple-points">Batch Mode Multiple Polynomials, multiple points</h4>

<p>In this case, we have $f_1, f_2,…, f_t \in \mathbb F_p[x]$ &amp; $t &lt; d$ with $z\in \mathbb F_p$. Let $C_{f_1},C_{f_2}, …, C_{f_t}$ be the commitments to these polynomials.</p>

<p>We also have $f’_1, f’_2,…, f’_t \in \mathbb F_p[x]$ with $t’ &lt; d$ &amp; $z’\in \mathbb F_p$.</p>

<p>Let $C_{f_1’},C_{f_2’}, …,C_{f_{t’}’}$</p>

<p>be the commitments to these polynomials.</p>

<p>And likewise $f’'_i$s, with $z’’$ and many more such sets.</p>

<p>Let’s, for a moment, assume we have only 2 such sets $f$ &amp; $f’$ &amp; batch them together. We can extend the same method for any number of such sets.</p>

<p>In the multiple polynomial, same point protocol, $F$ &amp; $v$ were computed, now we also have $F’$ &amp; $v’$. $F$ &amp; $F’$ can be computed in parallel. And likewise $v$ &amp; $v’$. So similar to $(Eq 2)$, we have</p>

<p>$C_f \cdot (a-z) \stackrel {?}{=} F - v$</p>

<p>$C_{f’} \cdot (a-z’) \stackrel {?}{=} F’ - v’$</p>

<p>Verifier sends a random $r \in \mathbb F_p$, and Prover uses it to combine the above 2 equatons in a linearly independent way so that they can be tested together. This trick is <a href="/PLONKWHY#linear-independence">explained here</a>.</p>

<p>$C_f(a-z) + r\cdot C_{f’}\cdot (a-z’) \stackrel {?}{=} F + rF’ - v - rv’$</p>

<p>Let $H = F+rF’ - v - rv’$</p>

<p>$C_f(a-z) + r\cdot C_{f’}\cdot (a-z’) \stackrel {?}{=} H$</p>

<p>$a \cdot C_f  + ra \cdot C_{f’} \stackrel {?}{=} H + z\cdot C_f + z’r\cdot C_{f’}$</p>

<p>$a(C_f  + r \cdot C_{f’}) \stackrel {?}{=} H + z\cdot C_f + z’r\cdot C_{f’}$</p>

<p>Using pairings,</p>

<p>$e(a(C_f  + r \cdot C_{f’}), G) \stackrel {?}{=} e(H + z\cdot C_f + z’r\cdot C_{f’}, G)$</p>

<p>Using the bilinearity property</p>

<p>$e(C_f  + r \cdot C_{f’}, aG) \stackrel {?}{=} e(H + z\cdot C_f + z’r\cdot C_{f’}, G)$</p>

<p>So all the terms in the above are known &amp; the verifier can check if the equality holds or not.</p>

<p>For more than 2 sets, we will combine them linearly independent using $\lbrace 1, r, r^2, r^3, …\rbrace$ as explained.</p>

<hr />
<p>One of the advantages of the KZG PCS is that the commitment size is constant. Irrespective of how long the polynomial is (i.e. degree of the polynomial), the commitment is always just one element of the group $\mathbb G$. Likewise, the evaluation proof is also a commitment, so there again, the size is constant for the evaluation proof both at a single value and also in batch mode.</p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FKate%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Weil Pairing and the MOV attack on Elliptic Curve Cryptography</title><link href="https://risencrypto.github.io/WeilMOV/" rel="alternate" type="text/html" title="Weil Pairing and the MOV attack on Elliptic Curve Cryptography" /><published>2022-11-08T00:00:00+00:00</published><updated>2022-11-08T00:00:00+00:00</updated><id>https://risencrypto.github.io/WeilMOV</id><content type="html" xml:base="https://risencrypto.github.io/WeilMOV/"><![CDATA[<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    tex2jax: {
      inlineMath: [ ['$','$'], ["\\(","\\)"] ],
      processEscapes: true
    }
  });
</script>

<script type="text/javascript" charset="utf-8" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>

<script type="text/javascript" charset="utf-8" src="https://vincenttam.github.io/javascripts/MathJaxLocal.js">
</script>

<h2 id="why-elliptic-curve-cryptography">Why Elliptic Curve Cryptography?</h2>

<p><strong>Q.</strong> Why does modern cryptography prefer the discrete log problem over the additive group of points on an Elliptic Curve defined over a Finite Field rather than integer factorization or the discrete log problem over the multiplicative group of a Finite Field?</p>

<p><strong>A.</strong> A cryptographic algorithm is said to have a security level of $n$ bits if the best known attack can break it in $2^n$ steps. So if the naive brute force/exhaustive search is the best known attack for any algorithm the security level will be same as the key size in bits. However most asymmetric algorithms have much better attacks than the naive attack &amp; hence their security level is lesser than the key size. For e.g. the Discrete Log problem on which Diffie Hellman is based on has a very powerful attack called as Index Calculus, which can solve the Discrete Log problem in sub-exponential time. To compensate for this attack, we have to use very large key sizes in DH. To get 112 bit security, DH needs 2048 bit key size.</p>

<p>Index Calculus uses smooth numbers. Likewise, the General Number Field Sieve for Integer Factorzation using smooth numbers means RSA also requires a 2048 bit key size to get 112 bit security. Unlike the multiplicative group of a Finite Field, the group of Elliptic Curve points doesn’t have a straightforward notion of smoothness &amp; any methods similiar to Index Calculus haven’t been discovered in this group. Hence in Elliptic Curve Cryptography, you can get 112 bit security with just 224 bit Key Size.</p>

<p>Key Size for 112 bit security</p>

\[\begin{array}{c|c}\hline
 {\textbf{Algorithm}} &amp; {\textbf{Size}} \\\hline
 RSA &amp; 2048 \\\hline
 DH &amp; 2048 \\\hline
 ECDH &amp; 224 \\\hline
\end{array}\]

<p><em>Note:</em> For asymmetric algorithms like the above, key size typically refers to the size of the modulus.</p>

<p>So one can use an elliptic curve group that is smaller in size than a regular DH group while maintaining the same level of security. In most situations, the result is smaller key sizes, bandwidth savings and faster operations.</p>

<h2 id="the-mov-attack">The MOV attack</h2>

<p>The MOV (Menezes-Okamoto-Vanstone) attack transforms a Discrete Log problem in an Elliptic Curve Group into a Discrete Log Problem in the Multiplicative Group of a Finite Field - i.e. ECDLP to DLP. Since Index Calclus is possible in DLP, it may become easier to solve the DLP &amp; thus solve the ECDLP.</p>

<p><em>Some pre-requisite topics before we discuss the MOV attack</em></p>

<h3 id="what-is-a-bilinear-map">What is a bilinear map?</h3>

<p>We can look at linear &amp; bilinear maps using the example of Vector Spaces.</p>

<p>Let</p>

<ul>
  <li>$U, V, W$ be vector spaces</li>
  <li>$\lbrace u, u_1, u_2  \in U \rbrace$ , $\lbrace v, v_1, v_2 \in V \rbrace$</li>
  <li>$\alpha$ is a scalar</li>
</ul>

<p> </p>

<p>$f_1 : V \mapsto W \space (f_1$ is a map from $V$ to $W$)</p>

<p>$f_1$ is a <strong>linear map</strong> if</p>

<ul>
  <li>
    <p>$f_1(v_1 + v_2) = f_1(v_1) + f_1(v_2)$</p>
  </li>
  <li>
    <p>$f_1(\alpha v) = \alpha f_1(v)$</p>
  </li>
</ul>

<p> </p>

<p>$f_2 : U$ X $V \mapsto W \space (f_2$ is a map from $U$ X $V$ to $W)$</p>

<p>$f_2$ is a <strong>bilinear map</strong> if</p>

<ul>
  <li>
    <p>$f_2(u_1 + u_2, v) = f_2(u_1, v) + f_2(u_2, v)$</p>
  </li>
  <li>
    <p>$f_2(u, v_1 + v_2) = f_2(u, v_1) + f_2(u, v_2)$</p>
  </li>
  <li>
    <p>$f_2(\alpha u, v) = \alpha f_2(u, v) = f_2(u, \alpha v)$</p>
  </li>
</ul>

<p>This means that the map is linear in $u$ if $v$ is fixed &amp; is linear in $v$ if $u$ is fixed.</p>

<h3 id="roots-of-unity">Roots of Unity</h3>

<p>$t$ is an $n$-th root of unity if $t^n = 1$. If you are unfamiliar with “Roots of Unity”, you can take a look at this <a href="https://www.youtube.com/watch?v=bme6sLcpYgA">video</a>.</p>

<p>However, the video talks about the complex roots of unity and not in other structures like a finite field.</p>

<p>Let’s consider roots of unity in a finite field of prime order say $\mathbb F_5 = \lbrace 0, 1, 2, 3, 4 \rbrace$. Every element in this field except for $0$ when raised to $4$ gives $1$. For e.g. $3^4 \bmod 5 \equiv 1$. So every element in the field $\mathbb F_5$ is a $4$-th root of unity. This is because for any non zero element $a \in \mathbb F_q$, we know that $a^q = a$ &amp; hence $a^{q - 1} = 1$ by Lagrange’s Theorem. So every element $a$ in a finite field of prime order $q$ is a ($q-1$)-th root of unity.</p>

<p>Next let’s consider Extension Fields, fields of prime power order i.e. $\mathbb F_{q^t}$</p>

<p>The order of all non-zero $a \in \mathbb F_{q^t}$ is either $q^{t}-1$ or something which divides $q^{t}-1$.</p>

<p>Hence $a^{q^t - 1} = 1$ for all non-zero $a \in \mathbb F_{q^t}$</p>

<p>Hence every non-zero element in an extension field also is a ($q^{t}-1$)-th root of unity.</p>

<h3 id="embedding-degree">Embedding Degree</h3>

<p>Let $E$ be an elliptic curve defined over a prime field $\mathbb F_q$. Let $P$ be a point of order $m$ where $m$ is prime &amp; is also coprime with $q$.</p>

<p>If $k$ is the smallest positive integer such that</p>

<p>$q^k \equiv 1 \bmod m$</p>

<p>then $k$ is called as the embedding degree of the curve $E(\mathbb F_q)$ with respect to $m$.</p>

<h3 id="torsion-points-and-torsion-groups">Torsion Points and Torsion Groups</h3>

<p>$E$ is an elliptic curve defined over a prime field $\mathbb F_q$. A point $P \in E(\mathbb F_q)$ satisfying $mP = \mathcal O$ is called a $m$-torsion point. The subgroup of all $m$-torsion points in $E(\mathbb F_q$) is called the $m$-torsion subgroup of $\mathbb F_q$ &amp; is denoted by $E(\mathbb F_q)[m] = \lbrace P \in E : mP = \mathcal O \rbrace$.</p>

<p>Since the Extension field $\mathbb F_{q^c}$ is bigger than base field $\mathbb F_q$, it’s likely that the $m$-torsion group of the curve over the Extension Field is bigger than the $m$-torsion group of the curve base field. We get the biggest $m$-torsion group when $c$ is equal to the embedding degree of the Curve at $m$ - i.e. going to a bigger extension field than $\mathbb F_{q^k}$ doesn’t add any more $m$-torsion points. Hence $E(\mathbb F_{q^k})[m]$ is called the full $m$-torsion group (where $k$ is the embedding degree of the Curve with respect to $m$).</p>

<p>The Full Torsion Group has multiple subgroups, we use 2 of these subgroups in the Weil Pairing.</p>

<ul>
  <li>
    <p>$\mathbb G_1$ - all points in this subgroup are in the Curve over the base field i.e. they are in $E(\mathbb F_q)$.</p>
  </li>
  <li>
    <p>$\mathbb G_2$ - all points in this subgroup are in $E(\mathbb F_{q^k})$ with none of them being in $E(\mathbb F_q)$. There are multiple such subgroups, it doesn’t matter which one is chosen.</p>
  </li>
</ul>

<h3 id="the-weil-pairing">The Weil Pairing</h3>

<p>Since $k$ is the embedding degree of the Curve with respect to $m$,</p>

<p>$q^k \equiv 1 \bmod m$</p>

<p>This can be written as $q^k = mx + 1$</p>

<p>$\therefore q^k - 1 = mx$</p>

<p>$\therefore m$ divides $q^k - 1$</p>

<p>Consider the Extension Field $\mathbb F_{q^k}$. The multiplicative group of this extension field i.e. $\mathbb F^{\star}_{q^k}$ excludes the element $0$ and hence it’s order is $q^k - 1$. Since $m$ divides the order of the multiplicative group, by the Fundamental Theorem of Cyclic Groups, it has a unique subgroup $\mathbb G_T$ of order $m$.</p>

<p>When the additional constraint $m \nmid (q - 1)$ is satisfied, the Weil pairing which is a map from $\mathbb G_1$ X $\mathbb G_2$ to the multipicative group $\mathbb G_T$ can be constructed.</p>

<p>$e_m : \mathbb G_1 \times \mathbb G_2 \mapsto G_T$</p>

<p>$e_m$ takes as input a pair of $m$-torsion points $A$ &amp; $B$ where $A \in \mathbb G_1$ and $B \in \mathbb G_2$. The map gives as output an $m^{th}$ root of unity $e_m(A,B)$. The output of the Weil Pairing when raised to $m$ always gives $1$ - i.e. ${e_m(A,B)}^m = 1$.</p>

<p>Note again that $\mathbb G_1$ &amp; $\mathbb G_2$ are Elliptic Curve Groups while $\mathbb G_T$ is a Multiplicative Group.</p>

<p>These are the properties of the Weil Pairing</p>

<ul>
  <li><strong>Bilinear:</strong></li>
</ul>

<p>The Right Hand Side of the Weil Pairing bilinearity is multiplicative rather than the additive bilinearity we saw earlier with Bilinear Maps of Vector Spaces.</p>

<p>$\quad e_m(A_1 + A_2, B) = e_m(A_1, B).e_m(A_2,B)$</p>

<p>$\quad e_m(A, B_1 + B_2) = e_m(A, B_1).e_m(A,B_2)$</p>

<p>Let $G_1$ &amp; $G_2$ be the generators of the 2 Elliptic Curve Groups. Let $\alpha$ &amp; $\beta$ be scalars.</p>

<p>$\quad e_m(\alpha G_1, \beta G_2) = e_m(\beta G_1, \alpha G_2) = e_m(\alpha\beta G_1, G_2) = e_m(G_1, \alpha\beta G_2) = e_m(G_1, \alpha G_2)^{\beta} = e_m(G_1, G_2)^{\alpha\beta}$</p>

<ul>
  <li><strong>Identity:</strong></li>
</ul>

<p>   $e_m(A, A) = 1$ for all $A \in E[m]$.</p>

<ul>
  <li><strong>Alternation:</strong></li>
</ul>

<p>   $e_m(A,B) = e_m(B,A)^{-1}$ for all $A, B \in E[m]$.</p>

<ul>
  <li><strong>Non-Degeneracy:</strong></li>
</ul>

<p>  $e_m(A, \mathcal O) = 1$ for all $A \in E[m]$</p>

<p>  If $e_m(A, B) = 1$ for all  $B \in E[m]$, then it means $A = \mathcal O$</p>

<h3 id="finally-the-mov-attack">Finally, the MOV Attack</h3>

<p>Consider an Elliptic Curve $E$ over the field $\mathbb F_q$</p>

<p>We are given points $P$ &amp; $Q$ both of prime order $m$ such that</p>

<p>$Q = rP$</p>

<p>We have to find $r$. This is the Elliptic Curve Discrete Log problem.</p>

<p>Since $P$ is a $m$-torsion point &amp; it’s a point on the Curve over the base field, $P, Q \in \mathbb G_1$</p>

<p><strong>The Steps:</strong></p>

<p><strong>1)</strong> Compute the order of the Elliptic Curve over the Extension field i.e. $n = \text# E(\mathbb F_{q^k})$. Since the $m$-Torsion group of $E(\mathbb F_q)$ is a subgroup of $E(\mathbb F_{q^k})$, $m$ divides $n$ (Lagrange’s Theorem)</p>

<p><strong>2)</strong> Choose a random point $T \in E(\mathbb F_{q^k})$ such that $T \notin E(\mathbb F_q)$</p>

<p><strong>3)</strong> Compute $S = (\frac {n}{m}) T$. If $S = \mathcal O$, then go back to step 2 &amp; chose another random point $T$. If it’s not $\mathcal O$, then it’s a point of order $m$ as shown below</p>

<p>$S = (\frac {n}{m}) T$</p>

<p>$\therefore mS = nT$</p>

<p>Let $t$ be the order of $T$. By Lagrange’s Theorem, $t$ divides the order of $E(\mathbb F_{q^k})$. i.e. $t$ divides $n$. So $n$ can be written as $n = dt$ for some $d$.</p>

<p>$\therefore mS = dtT$</p>

<p>Since $tT = \mathcal O$, $dtT = \mathcal O$.</p>

<p>$\therefore mS = \mathcal O$</p>

<p>So the order of $S$ is $m$.</p>

<p><strong>4)</strong></p>

<p>$P, rP \in \mathbb G_1$</p>

<p>$S \in \mathbb G_2$</p>

<p>Compute the 2 Weil Pairing values</p>

<p>$u = e_m(P, S)$</p>

<p>$v = e_m(rP, S)$  ($rP$ is $Q$ which we know)</p>

<p>$u, v \in \mathbb F_{q^k}$</p>

<p>Since the Weil Pairing is bilinear &amp; $r$ is a scalar,</p>

<p>$v = {e_m(P, S)}^r$</p>

<p>Since $u = e_m(P, S)$, we get</p>

<p>$v = u^r$.</p>

<p>This is the Discrete Log problem(DLP) in the multiplicative group of $\mathbb F_{q^k}$. So we have transformed the ECDLP  $Q = rP$ into the DLP $u = v^r$.</p>

<p><strong>5)</strong> If $q^k$ is not too large, then $u=v^r$ can be solved using Index Calculus &amp; $r$ can be found. So we have solved $Q = rP$</p>

<p>If the embedding degree $k$ is very large, transforming the ECDLP on $E(\mathbb F_q)$ to a DLP on $\mathbb F_{q^k}$ won’t help. But if the the embedding degree is small enough, then the DLP can become significantly easier. For e.g., a curve with a 256-bit $q$ usually offers 128 bits of security. But if it has an embedding degree $2$, then we can map the discrete logarithm to the field $\mathbb F_{q^2}$ which offers only 60 bits of security which can be broken by Index Calculus.</p>

<h2 id="mitigation">Mitigation</h2>

<p>To ensure that an elliptic curve $E$ defined over $\mathbb F_q$ is immune to the MOV attack, it is sufficient to check that $m$, the order of the base point $P \in E(\mathbb F_q)$, does not divide $q^k - 1$ for all small $k$ for which the $DLP$ in $\mathbb F^{\star}_{q^k}$ is considered tractable. If the order of $P$, i.e. $m \gt 2^{160}$, then it suffices to check this condition for all $k \in [1,20]$.</p>

<p><em>The actual construction/computation of the Weil Pairing using Rational Functions is beyond the scope of this post.</em></p>

<p><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Frisencrypto.github.io%2FWeilMOV%2F&amp;label=Visitors&amp;icon=github&amp;color=%23198754&amp;message=&amp;style=flat&amp;tz=Asia%2FCalcutta" alt="Badge" /></p>]]></content><author><name>RisenCrypto</name></author><summary type="html"><![CDATA[]]></summary></entry></feed>