arnaucube
arnaucube/arnaucube.comPublic Self-hosted repository
arnaucube.com/blog/powersoftau.html
blog/powersoftau.htmlRaw
  1<!DOCTYPE html>
  2<html lang="en">
  3
  4  <head>
  5    <meta name="description" content="In the following notes we go over the ideas behind the Powers of Tau ceremony, how participants contribute and how the contributions are verified (logic & code). We focus on the Ethereum's upcoming KZG-Ceremony." />
  6    <meta charset="utf-8">
  7    <title> Implementing the powers of tau contributor - arnaucube - blog</title>
  8    <meta name="title" content=" Implementing the powers of tau contributor - arnaucube - blog">
  9    <meta name="description" content="In the following notes we go over the ideas behind the Powers of Tau ceremony, how participants contribute and how the contributions are verified (logic & code). We focus on the Ethereum's upcoming KZG-Ceremony.">
 10
 11    <meta property="og:title" content=" Implementing the powers of tau contributor - arnaucube - blog" />
 12    <meta property="og:description" content="In the following notes we go over the ideas behind the Powers of Tau ceremony, how participants contribute and how the contributions are verified (logic & code). We focus on the Ethereum's upcoming KZG-Ceremony." />
 13    <meta property="og:url" content="https://arnaucube.com/blog/powersoftau.html" />
 14    <meta property="og:type" content="article" />
 15    <meta property="og:image" content="https://arnaucube.com/blog/" />
 16    <meta name="twitter:title" content=" Implementing the powers of tau contributor - arnaucube - blog">
 17    <meta name="twitter:description" content="In the following notes we go over the ideas behind the Powers of Tau ceremony, how participants contribute and how the contributions are verified (logic & code). We focus on the Ethereum's upcoming KZG-Ceremony.">
 18    <meta name="twitter:image" content="https://arnaucube.com/blog/">
 19    <meta name="twitter:card" content="summary_large_image">
 20    <meta name="author" content="arnaucube">
 21
 22    <link rel="icon" type="image/png" href="img/logoArnauCubeFavicon.png">
 23
 24    <meta name="viewport" content="width=device-width, initial-scale=1">
 25
 26    <link href="css/bootstrap.min.css" rel="stylesheet">
 27    <link rel="stylesheet" href="css/style.css">
 28
 29    <!-- highlightjs -->
 30    <!-- <link rel="stylesheet" href="js/highlightjs/atom-one-dark.css"> -->
 31    <link rel="stylesheet" href="js/highlightjs/atom-one-light.css">
 32    <!-- <link rel="stylesheet" href="js/highlightjs/gruvbox-dark.css"> -->
 33    <script src="js/highlightjs/highlight.pack.js"></script>
 34
 35    <!-- katex -->
 36    <link rel="stylesheet" href="js/katex/katex.min.css">
 37  <link rel="alternate" type="application/rss+xml" title="arnaucube - blog RSS" href="https://arnaucube.com/blog/rss.xml">
 38</head>
 39
 40  <body>
 41
 42    <!-- o_gradient_background" -->
 43    <nav id="mainNav" class="navbar navbar-default navbar-fixed-top"
 44                      style="height:50px;font-size:100%;">
 45      <div class="container">
 46        <div style="float:left;">
 47        <a href="/blog" style="color:#000;display:inline-block;">blog</a>
 48        <span style="margin-right:20px; margin-left:20px;">|</span>
 49        <a href="/notes.html" style="font-size:90%;color:#000;display:inline-block;">notes</a>
 50        </div>
 51        <div style="float:right;">
 52          <a href="/" style="color:#000;display:inline-block;margin-right:10px;">arnaucube.com</a>
 53          <a href="/blog/rss.xml" target="_blank"
 54            type="application/rss+xml" title="subscribe via RSS" aria-label="subscribe via RSS">
 55              <img width="12px;" src="img/rss.png" />
 56          </a>
 57          <div class="onoffswitch" style="margin-left:0px;display:inline-block;" title="change theme">
 58            <input onclick="switchTheme()" type="checkbox" name="onoffswitch" class="onoffswitch-checkbox"
 59              id="themeSwitcher">
 60            <label class="onoffswitch-label" for="themeSwitcher"></label>
 61          </div>
 62        </div>
 63      </div>
 64      <!-- <img style="height:5px; width:100%; margin-top:8px;" src="img/gradient-line.jpg" /> -->
 65    </nav>
 66
 67
 68    <div class="container" style="max-width:800px;">
 69        <br>
 70        <div style="background:#cccccc; border:2px gray solid; padding:5px; width:80%;margin-left:auto; margin-right:auto; margin-bottom:5px;">
 71          <i>Note: this blog is human-written, no AI generated content.</i>
 72        </div>
 73
 74      <h1>Implementing the powers of tau contributor</h1>
 75
 76<p><em>2023-01-02</em></p>
 77
 78<p>In the following notes we go over the ideas behind the <em>Powers of Tau</em> ceremony, how participants contribute and how the contributions are verified.</p>
 79
 80<p>The powers of tau are used in schemes such as KZG Commitments, and by consequence in the Plonk-KZG and in Verkle Trees use cases, which the later ones are in the Ethereum roadmap, but probably the ceremony output will be used in many other applications.
 81The ceremony is named also as <em>Trusted Setup Ceremony</em>, and <em>SRS</em> (Structured Reference String) in Plonk and Sonic papers.</p>
 82
 83<p>Specifically these notes focus on the powers of tau ceremony that is <a href="https://github.com/ethereum/kzg-ceremony">being prepared in Ethereum</a>. For learning about the specifics of the powers of tau reasoning, I&rsquo;ve used the following two documents:</p>
 84
 85<ul>
 86<li><a href="https://github.com/ethereum/kzg-ceremony/blob/main/KZG10-Ceremony-audit-report.pdf">KZG10-Ceremony-audit-report.pdf, by SECBIT Labs</a></li>
 87<li><a href="https://arxiv.org/abs/1906.07221v1"><em>Why and how zkSNARKs work</em>, by Maksym Petkus</a></li>
 88</ul>
 89
 90<p>Additionally, <a href="https://vitalik.ca/general/2022/03/14/trustedsetup.html">this article by Vitalik Buterin</a> explains the ideas behind trusted setups.</p>
 91
 92<p>The contents of these notes are distributed as follows:
 93<br><span style="margin-right:40px;"></span>
 94    <a style="color:gray;" href="#the-main idea">The main idea</a>
 95<br><span style="margin-right:40px;"></span>
 96    <a style="color:gray;" href="#preliminaries">Preliminaries</a>
 97<br><span style="margin-right:40px;"></span>
 98    <a style="color:gray;" href="#participant-contribution">Participant contribution</a>
 99<br><span style="margin-right:40px;"></span>
100    <a style="color:gray;" href="#proof-of correct computation">Proof of correct computation</a>
101<br><span style="margin-right:40px;"></span>
102    <a style="color:gray;" href="#contribution-verification">Contribution verification</a>
103<br><span style="margin-right:40px;"></span>
104    <a style="color:gray;" href="#full-flow">Full flow</a>
105<br><span style="margin-right:40px;"></span>
106    <a style="color:gray;" href="#conclusions">Conclusions</a></p>
107
108<p>Across these notes some snippets of Sage code are provided, the full Sage code can be found <a href="https://github.com/arnaucube/math/blob/master/powersoftau.sage">here</a>, and also a <a href="https://github.com/arnaucube/eth-kzg-ceremony-alt">full implementation in Go</a> which also contains a CLI to participate in the upcomming Ethereum KZG-Ceremony.</p>
109
110<h3>The main idea</h3>
111
112<p>The main idea is that we want to compute <span class="math inline">\(\tau^0, \tau^1, \tau^2, \ldots, \tau^{n-1}\)</span>, where <span class="math inline">\(\tau\)</span> should be unknown. In order to achieve this, we use some technics to combine different <span class="math inline">\(\tau\)</span>s from different contributors, in a way where we obtain the powers of a tau which is a combination of the different secret taus (<span class="math inline">\(\tau_{p_i}\)</span>) of the different participants.</p>
113
114<p>The <span class="math inline">\(\tau_{p_i}\)</span> should be secret for each participant, furthermore, it should be generated from some source of randomness and destroyed at the end.</p>
115
116<p>As we&rsquo;ve mentioned, we want to come up with the powers of tau where tau is a combination of the taus from all the participants, in a way where as long as there is at least one honest participant, which does not share their part of the final tau, the combined-tau can not be recovered and the ceremony is assumed to be safe.</p>
117
118<p>This is important, because if somebody has knowledge of the tau value, could generate fake proofs. As an example <a href="https://medium.com/qed-it/how-toxic-is-the-waste-in-a-zksnark-trusted-setup-9b250d59bdb4">this article by Kobi Gurkan</a> shows how fake BCTV14a proofs can be generated if tau is known.</p>
119
120<p>This is relevant in the context of <a href="https://arnaucube.com/blog/kzg-commitments.html">KZG Commitments</a>, specially in the roadmap of Ethereum.
121Ethereum will run the Ceremony which will be used at least in <a href="https://eips.ethereum.org/EIPS/eip-4844">EIP-4844</a>. That&rsquo;s why EF&rsquo;s is encouraging people to participate in various ways, as the Ceremony is considered safe as long as there is at least one honest participant, with the idea that if you participate, assuming that you consider yourself honest, you can consider the Ceremony safe.</p>
122
123<p>The output of the ceremony will be used in the Ethereum VerkleTrees, which uses KZG Commitments, but also it will be useful for Plonk-KZG proofs.</p>
124
125<p>So the best way to trust the output of the ceremony is by becoming a participant yourself!, Furhermore, by participating with your own code ^^</p>
126
127<h3>Preliminaries</h3>
128
129<p><strong>Pairing</strong><br>
130We will try to focus only in the concepts that we strictly need for the implementation, so we will treat Pairings as a black box with some simplified properties.</p>
131
132<p>For our use case, we use asymmetric bilinear pairings. We can see an asymmetric bilinear pairing as a function that maps an element from the group <span class="math inline">\(\mathbb{G_1}\)</span> and another one from <span class="math inline">\(\mathbb{G_2}\)</span> into an el element of the group <span class="math inline">\(\mathbb{G_T}\)</span>.</p>
133<p><span class="math display">\[e: \mathbb{G_1} \times \mathbb{G_2} \longrightarrow \mathbb{G_T}\]</span></p><p>For our use case, we&rsquo;ll focus only on one property, <em>bilinearity</em>.</p>
134
135<p>Let <span class="math inline">\(a, b \in \mathbb{F_q}\)</span>, <span class="math inline">\(\mathbb{G}_1 = \langle G \rangle\)</span> and <span class="math inline">\(\mathbb{G}_2 = \langle H \rangle~\)</span> (In other words, <span class="math inline">\(G\)</span> is the generator of <span class="math inline">\(\mathbb{G}_1\)</span>, and <span class="math inline">\(H\)</span> is the generator of <span class="math inline">\(\mathbb{G}_2\)</span>).</p>
136
137<p>Then, the bilinearity property tells us that</p>
138<p><span class="math display">\[e(a \cdot G,~b \cdot H) = e((a \cdot b) \cdot G,~H) = e(G,~(a \cdot b) \cdot H)\]</span></p><p>For better readability, we will use the following notation to represent the scalar point multiplication:</p>
139<p><span class="math display">\[[x]_1 = x \cdot G \in \mathbb{G}_1\newline
140[x]_2 = x \cdot H \in \mathbb{G}_2\]</span></p><p>So, our previous bilinearity example would look like</p>
141<p><span class="math display">\[e([a]_1, [b]_2) = e([a \cdot b]_1, [1]_2) = e([1]_1, [a \cdot b]_2)\]</span></p><p>In our practical use case, we use the <a href="https://hackmd.io/@benjaminion/bls12-381">BLS12-381</a> pairing, where <span class="math inline">\(\mathbb{G}_1, \mathbb{G}_2\)</span> are elliptic curve groups, thus the points <span class="math inline">\(G, H\)</span> are elliptic curve points.</p>
142
143<p><strong>Code</strong><br>
144For the code examples we&rsquo;ll use <a href="https://www.sagemath.org">SageMath</a>, but the code would look quite similar in Python, and the same logic can be implemented in any language.</p>
145
146<h3>Participant contribution</h3>
147
148<p>In the context of SRS (Structured Reference String), the powers of tau consist of an array containing the scalar multiplication of the generator point by each power of tau, eg. <span class="math inline">\(\tau^0 \cdot G,~\tau^1 \cdot G,~\tau^2 \cdot G,~\tau^3 \cdot G \ldots\)</span></p>
149
150<p>For our case, we&rsquo;ll generate <span class="math inline">\(n\)</span> powers of tau on <span class="math inline">\(\mathbb{G}_1\)</span>, and <span class="math inline">\(m\)</span> on <span class="math inline">\(\mathbb{G}_2\)</span>. We will denote the combination of both <span class="math inline">\(\mathbb{G}_1\)</span> and <span class="math inline">\(\mathbb{G}_2\)</span> powers of tau by SRS.</p>
151
152<p>Each participant will obtain the previous-participant generated SRS, which is formed by</p>
153<p><span class="math display">\[\{ [\tau^0]_1, [\tau^1]_1, [\tau^2]_2, \ldots, [\tau^{n-1}]_1 \},\\
154\{ [\tau^0]_2, [\tau^1]_2, [\tau^2]_2, \ldots, [\tau^{m-1}]_2 \}\]</span></p><p>for simplicity, we will represent it as</p>
155<p><span class="math display">\[\{~[~\tau^i]_1~\}^{n-1}_{i=0},~\{~[~\tau^i]_2~\}^{m-1}_{j=0}\]</span></p><p>Each participant generates their secret random tau <span class="math inline">\(\tau_p\)</span>, which to avoid confusion we will denote as <span class="math inline">\(p \in \mathbb{F}_r\)</span>. From it, the participant can compute <span class="math inline">\([p]_2 \in \mathbb{G}_2\)</span>.</p>
156
157<p>Then the participant proceeds to update the reference string (SRS), by multiplying each element by <span class="math inline">\(p^i\)</span>:</p>
158<p><span class="math display">\[\{~ p^i \cdot [~ \tau^i]_1~\}^{n-1}_{i=0},~\{~ p^i \cdot [~\tau^i]_2~\}^{m-1}_{j=0}\]</span></p><p>which, by the properties of scalar multiplication of a point, is equivalent to</p>
159<p><span class="math display">\[\{~ [~ (p \cdot \tau)^i]_1~\}^{n-1}_{i=0},~\{~ [~ (p \cdot \tau)^i]_2~\}^{m-1}_{j=0}\]</span></p><p>and we denote <span class="math inline">\(p \cdot \tau\)</span> as <span class="math inline">\(\tau'\)</span>, so we can write the previous expression as</p>
160<p><span class="math display">\[\{~[~\tau'^i]_1~\}^{n-1}_{i=0},~\{~[~\tau'^i]_2~\}^{m-1}_{j=0}\]</span></p><p>which is</p>
161<p><span class="math display">\[\{ [(\tau \cdot p)^0]_1, [(\tau \cdot p)^1]_1, [(\tau \cdot p)^2]_2, \ldots, [(\tau \cdot p)^{n-1}]_1 \},\\
162\{ [(\tau \cdot p)^0]_2, [(\tau \cdot p)^1]_2, [(\tau \cdot p)^2]_2, \ldots, [(\tau \cdot p)^{m-1}]_2 \}\]</span></p><p>Notice that the contributor does not know the previous <span class="math inline">\(\tau\)</span>, but can obtain <span class="math inline">\((\tau \cdot p)^i\)</span>.</p>
163
164<p><br><br>
165We can express the previous logic as follows:</p>
166
167<pre><code class="language-python">def compute_contribution(new_tau, prev_srs):
168    g1s = [None] * len(prev_srs[0])
169    g2s = [None] * len(prev_srs[1])
170    srs = [g1s, g2s]
171    Q = e.r
172
173    # compute [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁, where n = len(prev_srs.G1s)
174    for i in range(0, len(prev_srs[0])):
175        srs[0][i] = (new_tau^i) * prev_srs[0][i]
176    
177    # compute [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂, where n = len(prev_srs.G2s)
178    for i in range(0, len(prev_srs[1])):
179        srs[1][i] = (new_tau^i) * prev_srs[1][i]
180
181    return srs
182</code></pre>
183
184<h3>Proof of correct computation</h3>
185
186<p>The participant will compute the proof, which consists of</p>
187<p><span class="math display">\[\pi = ([\tau']_1,~[p]_2)\]</span></p><p>which is equivalent to <span class="math inline">\(\pi = (\tau' \cdot G,~p \cdot H) = ((p \cdot \tau) \cdot G,~p \cdot H)\)</span></p>
188
189<p>In the next section we will see how this is used to verify the contribution correct computation.</p>
190
191<p><br>
192We implement this logic as follows:</p>
193
194<pre><code class="language-python">def generate_proof(tau, prev_srs, new_srs):
195    # g_1^{tau'} = g_1^{p * tau} = SRS_G1s[1] * p
196    g1_ptau = prev_srs[0][1] * tau
197    # g_2^{p}
198    g2_p = tau * e.G2
199    return [g1_ptau, g2_p]
200</code></pre>
201
202<h3>Contribution verification</h3>
203
204<p>This is the interesting part. We want to check that the new SRS is well computed from the previous SRS together with the new tau. We want to avoid accepting contributions that do not follow the powers of tau structure, or that contain empty elements or that do not derive from the previous SRS.</p>
205
206<p>Following the powers of tau structure means that</p>
207<p><span class="math display">\[\tau'^{i+1} = \tau' \cdot \tau'^i ~~\forall~i \in [1, n-1]\]</span></p><p>And the relation between the new SRS and the previous SRS is</p>
208<p><span class="math display">\[\tau' = \tau \cdot p\]</span></p><p>where <span class="math inline">\(\tau\)</span> is the secret element from the previous SRS and <span class="math inline">\(p\)</span> is the secret one from the new SRS, resulting in the combined <span class="math inline">\(\tau'\)</span>.</p>
209
210<p>Now, we&rsquo;re interested into how we can check these relations in the context of the SRS elements. A new contribution can be verified as follows:</p>
211
212<ol>
213<li><p>Check that elements of the new SRS are non-empty, non-zero and in the correct prime order subgroups.</p></li>
214
215<li><p>Get the proof (<span class="math inline">\(\pi = ([\tau']_1, [p]_2)\)</span>), and confirm that the 1st element is equal to the element in position 1 <span class="math inline">\([\tau'^1]_1\)</span> of the new SRS (which corresponds to <span class="math inline">\(\tau'\)</span> powered to <span class="math inline">\(1\)</span>).</p></li>
216
217<li><p>Check that <span class="math inline">\(\tau'\)</span> (the new SRS) is correctly related to <span class="math inline">\(\tau\)</span> (the previous SRS).</p>
218
219<p>To check this, we rely on the pairing properties and we use the proof value generated by the contributor, which consists of <span class="math inline">\([p]_2\)</span></p>
220<p><span class="math display">\[e([\tau]_1, [p]_2) \stackrel{?}{=} e([\tau']_1, [1]_2)\]</span></p><p>We can see how this holds, as <span class="math inline">\(\tau' = p \cdot \tau\)</span>, and by the bilinear property of the pairing (see <a href="#preliminaries">Preliminearies section</a>) we have <span class="math inline">\(e(a \cdot G, b \cdot H) = e((a \cdot b) \cdot G, H)\)</span>, which in our notation is represented as</p>
221<p><span class="math display">\[e([a]_1, [b]_2) = e([a \cdot b]_1, [1]_2)\]</span></p><p>by applying this to our case we can see that:</p>
222<p><span class="math display">\[e([\tau]_1, [p]_2) = e([\tau \cdot p]_1, [1]_2) = e([\tau']_1, [1]_2)\]</span></p></li>
223
224<li><p>Check if the new SRS follows the powers of tau structure:</p>
225<p><span class="math display">\[e([\tau'^i]_1, [\tau']_2) \stackrel{?}{=} e([\tau'^{i+1}]_1, [1]_2) ~~ \forall ~i \in [1, n-1]\]</span></p><p><span class="math display">\[e([\tau']_1, [\tau'^j]_2) \stackrel{?}{=} e([1]_1, [\tau'^{j+1}]_2) ~~ \forall ~i \in [1, m-1]\]</span></p><p>Which, again, by the bilinarity property, we can see that</p>
226<p><span class="math display">\[e([\tau'^i]_1, [\tau']_2) = e([\tau'^{i+1}]_1, [1]_2)\]</span></p><p>is enforcing that <span class="math inline">\(\tau'^i \cdot \tau'^1 = \tau'^{i+1}\)</span>.</p>
227
228<p>And the same for</p>
229<p><span class="math display">\[e([\tau']_1, [\tau'^j]_2) = e([1]_1, [\tau'^{j+1}]_2)\]</span></p><p>which checks that <span class="math inline">\(\tau'^1 \cdot \tau'^j = \tau'^{j+1}\)</span>.</p>
230
231<p>With this check, we&rsquo;re ensuring that each power of tau of the SRS is consistent with the previous one.</p></li>
232</ol>
233
234<p><br><br>
235The complete verification function would look like</p>
236
237<pre><code class="language-python">def verify(prev_srs, new_srs, proof):
238    # 1. check that elements of the newSRS are valid points
239    for i in range(0, len(new_srs[0])-1):
240        assert new_srs[0][i] != None
241        assert new_srs[0][i] != e.E1(0)
242	assert new_srs[0][i] in e.E1
243    for i in range(0, len(new_srs[1])-1):
244        assert new_srs[1][i] != None
245        assert new_srs[1][i] != e.E1(0)
246	assert new_srs[1][i] in e.E2
247
248    # 2. check proof.G1PTau == newSRS.G1Powers[1]
249    assert proof[0] == new_srs[0][1]
250
251    # 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prev_srs.G1s[1] (g₁^τ)
252	#   e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
253    assert e.pair(prev_srs[0][1], proof[1]) == e.pair(new_srs[0][1], e.G2)
254
255    # 4. check newSRS following the powers of tau structure
256    # i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n−1]
257    for i in range(0, len(new_srs[0])-1):
258        assert e.pair(new_srs[0][i], new_srs[1][1]) == e.pair(new_srs[0][i+1], e.G2)
259
260    # ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m−1]
261    for i in range(0, len(new_srs[1])-1):
262        assert e.pair(new_srs[0][1], new_srs[1][i]) == e.pair(e.G1, new_srs[1][i+1])
263</code></pre>
264
265<h3>Full flow</h3>
266
267<p>Now that we have the three methods (<em>compute_contribution, generate_proof, verify</em>), it&rsquo;s a matter of using them.</p>
268
269<p>First let&rsquo;s add a couple of helpers to our code:</p>
270
271<pre><code class="language-python"># here we import the BLS12-381 pairing machinery
272load(&quot;bls12-381.sage&quot;) # file from https://github.com/arnaucube/math/blob/master/bls12-381.sage
273e = Pairing()
274
275# this method generates a SRS filled by the generator points of G1 &amp; G2
276def new_empty_SRS(nG1, nG2):
277    g1s = [None] * nG1
278    g2s = [None] * nG2
279    for i in range(0, nG1):
280        g1s[i] = e.G1
281    for i in range(0, nG2):
282        g2s[i] = e.G2
283
284    return [g1s, g2s]
285</code></pre>
286
287<p>Let&rsquo;s do the flow:</p>
288
289<pre><code class="language-python"># generate a fake previous-SRS
290(prev_srs) = new_empty_SRS(5, 3)
291
292# set a random value to be used for our tau
293random = 12345 # this would be a random value
294tau = e.F1(random)
295
296# compute our contribution, from the previous SRS and our tau
297new_srs = compute_contribution(tau, prev_srs)
298
299# generate a proof of correct computation of our contribution
300proof = generate_proof(tau, prev_srs, new_srs)
301
302# verify the proof for the given prev_srs and the new_srs
303verify(prev_srs, new_srs, proof)
304</code></pre>
305
306<h2>Conclusions</h2>
307
308<p>As we&rsquo;ve seen, we can prove and verify the correct computation of the new SRS with few operations.</p>
309
310<p>From here the next thing would be to implement the <a href="https://github.com/ethereum/kzg-ceremony-specs/blob/master/apiSpec/sequencerApi.yml">interaction with the Sequencer</a>, in order to authenticate the participant, fetch the previous SRS, and send the new SRS and proof.</p>
311
312<p>You can find the Sage example that we&rsquo;ve been using <a href="https://github.com/arnaucube/math/blob/master/powersoftau.sage">here</a>, and a full Go implementation here: <a href="https://github.com/arnaucube/eth-kzg-ceremony-alt">https://github.com/arnaucube/eth-kzg-ceremony-alt</a> (which uses <a href="https://github.com/kilic/bls12-381">Kilic&rsquo;s BLS12-381 implementation</a>, and includes also the interaction with the Sequencer and a CLI).
313There is also the EF&rsquo;s rust implementation <a href="https://github.com/crate-crypto/small-powers-of-tau">small-powers-of-tau</a> which has been audited. The same logic can be implemented in the language of your choice.
314<br><br></p>
315
316<p><a href="https://github.com/arnaucube/eth-kzg-ceremony-alt" target="_blank" title="https://github.com/arnaucube/eth-kzg-ceremony-alt">
317<img src="img/posts/powersoftau/kzg-ceremony-screenshot.png" style="width:100%;" />
318<span style="font-size:80%; color:gray;font-style:italic;">Screenshot of the eth-kzg-ceremony-alt CLI after contributing to the testnet ceremony.</a>
319</a></p>
320
321<p>Another interesting piece is the <em>randomness generation</em>. In our example, for simplicity, tau was hardcoded in the code, but in the real world case we would use some source of randomness to generate our secret value. Here you can get <a href="https://www.youtube.com/watch?v=I4cDAqeEmpU">as creative as you can</a>, and probably we will see some cool approaches for the Ethereum-KZG-Ceremony.</p>
322
323<p>This ceremony output is quite important, as it will be used in many applications once available. It will be used in the Ethereum protocol for the KZG Commitments on EIP-4844, but also on many other applications (some of them unrelated to Ethereum!). For example, any (up to the degree upperbound) Plonk-KZG deployment could reuse this ceremony to avoid needing to compute their own.
324So it&rsquo;s important to gather a notable amount of participants in the ceremony, and probably participate to it by yourself! (as if you&rsquo;re contributing you know that at least there has been one honest contribution (you)).</p>
325
326<p>You can find more info on the Ethereum&rsquo;s KZG Ceremony here: <a href="https://ceremony.ethereum.org">https://ceremony.ethereum.org</a> (which includes also a nice contributor webapp to participate from the browser).</p>
327
328    </div>
329
330    <footer style="text-align:center; margin-top:100px;margin-bottom:50px;">
331      <div class="container">
332        <br>
333        <a href="/blog">Go to main</a>
334        <br><br>
335        <div class="row">
336          <ul class="list-inline">
337            <li><a href="https://twitter.com/arnaucube"
338                   style="color:gray;text-decoration:none;"
339                   target="_blank">twitter.com/arnaucube</a>
340            </li>
341            <li><a href="https://github.com/arnaucube"
342                   style="color:gray;text-decoration:none;"
343                   target="_blank">github.com/arnaucube</a>
344            </li>
345          </ul>
346        </div>
347        <div class="row" style="display:inline-block;">
348          Blog made with <a href="http://github.com/arnaucube/blogo/"
349                            target="_blank" style="color: gray;text-decoration:none;">Blogo</a>
350        </div>
351      </div>
352    </footer>
353
354    <script>
355    </script>
356    <script src="js/external-links.js"></script>
357    <script>hljs.initHighlightingOnLoad();</script>
358    <script defer src="js/katex/katex.min.js"></script>
359    <script defer src="js/katex/auto-render.min.js"></script>
360    <script>
361      document.addEventListener("DOMContentLoaded", function() {
362        renderMathInElement(document.body, {
363          displayMode: false,
364          // customised options
365          // • auto-render specific keys, e.g.:
366          delimiters: [
367            {left: '$$', right: '$$', display: true},
368            {left: '$', right: '$', display: false},
369            {left: "\\[", right: "\\]", display: true},
370            {left: "\\(", right: "\\)", display: false},
371            {left: "\\begin{equation}", right: "\\end{equation}", display: true}
372          ],
373          // • rendering keys, e.g.:
374          throwOnError : true
375        });
376      });
377
378      ///
379      let theme = localStorage.getItem("theme");
380      if ((theme === "light-theme")||(theme==null)) {
381          theme = "light-theme";
382          document.getElementById("themeSwitcher").checked = false;
383      } else if (theme === "dark-theme") {
384          theme = "dark-theme";
385          document.getElementById("themeSwitcher").checked = true;
386      }
387      document.body.className = theme;
388      localStorage.setItem("theme", theme);
389
390      function switchTheme() {
391        theme = localStorage.getItem("theme");
392        if (theme === "light-theme") {
393          theme = "dark-theme";
394          document.getElementById("themeSwitcher").checked = true;
395        } else {
396          theme = "light-theme";
397          document.getElementById("themeSwitcher").checked = false;
398        }
399        document.body.className = theme;
400        localStorage.setItem("theme", theme);
401
402        console.log(theme);
403      }
404    </script>
405    <script>
406    function tagLinks(tagName) {
407      var tags = document.getElementsByTagName(tagName);
408      for (var i=0, hElem; hElem =  tags[i]; i++) {
409        if (hElem.parentNode.className=="row postThumb") {
410          continue;
411        }
412        hElem.id = hElem.innerHTML.toLowerCase().replace(" ", "-");
413        hElem.innerHTML = "<a style='color:black!important;' href='#"+hElem.id+"'>"+hElem.innerHTML+"</a>";
414      }
415    }
416    tagLinks("h2");
417    tagLinks("h3");
418    tagLinks("h4");
419    tagLinks("h5");
420    </script>
421    <script>
422function generateTOC(tocContainerId = "toc") {
423    const tocContainer = document.getElementById(tocContainerId);
424    if (!tocContainer) return;
425
426    const headings = document.querySelectorAll("h2, h3, h4, h5, h6");
427    if (!headings.length) return;
428
429    // Generate IDs if missing
430    headings.forEach((heading, index) => {
431        if (!heading.id) {
432            heading.id =
433                heading.textContent
434                    .trim()
435                    .toLowerCase()
436                    .replace(/[^\w\s-]/g, "")
437                    .replace(/\s+/g, "-") +
438                "-" +
439                index;
440        }
441    });
442
443    const toc = document.createElement("ul");
444    let currentLevel = 1;
445    let currentList = toc;
446    const stack = [toc];
447
448    headings.forEach((heading) => {
449        const level = parseInt(heading.tagName.substring(1), 10);
450
451        const li = document.createElement("li");
452        const a = document.createElement("a");
453
454        a.href = "#" + heading.id;
455        a.textContent = heading.textContent;
456
457        li.appendChild(a);
458
459        if (level > currentLevel) {
460            for (let i = currentLevel; i < level; i++) {
461                const nestedList = document.createElement("ul");
462
463                const lastLi =
464                    currentList.lastElementChild ||
465                    currentList.appendChild(document.createElement("ul"));
466
467                lastLi.appendChild(nestedList);
468
469                stack.push(nestedList);
470                currentList = nestedList;
471            }
472        } else if (level < currentLevel) {
473            for (let i = currentLevel; i > level; i--) {
474                stack.pop();
475            }
476            currentList = stack[stack.length - 1];
477        }
478
479        currentList.appendChild(li);
480        currentLevel = level;
481    });
482
483    tocContainer.innerHTML = "";
484    tocContainer.appendChild(toc);
485}
486
487document.addEventListener("DOMContentLoaded", () => {
488    generateTOC();
489});
490    </script>
491    <script src="js/mermaid.min.js"></script>
492
493  </body>
494</html>
495