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="/blog/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
 69    <div class="container" style="margin-top:0px;max-width:800px;">
 70      <h1>Implementing the powers of tau contributor</h1>
 71
 72<p><em>2023-01-02</em></p>
 73
 74<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>
 75
 76<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.
 77The ceremony is named also as <em>Trusted Setup Ceremony</em>, and <em>SRS</em> (Structured Reference String) in Plonk and Sonic papers.</p>
 78
 79<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>
 80
 81<ul>
 82<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>
 83<li><a href="https://arxiv.org/abs/1906.07221v1"><em>Why and how zkSNARKs work</em>, by Maksym Petkus</a></li>
 84</ul>
 85
 86<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>
 87
 88<p>The contents of these notes are distributed as follows:
 89<br><span style="margin-right:40px;"></span>
 90    <a style="color:gray;" href="#the-main idea">The main idea</a>
 91<br><span style="margin-right:40px;"></span>
 92    <a style="color:gray;" href="#preliminaries">Preliminaries</a>
 93<br><span style="margin-right:40px;"></span>
 94    <a style="color:gray;" href="#participant-contribution">Participant contribution</a>
 95<br><span style="margin-right:40px;"></span>
 96    <a style="color:gray;" href="#proof-of correct computation">Proof of correct computation</a>
 97<br><span style="margin-right:40px;"></span>
 98    <a style="color:gray;" href="#contribution-verification">Contribution verification</a>
 99<br><span style="margin-right:40px;"></span>
100    <a style="color:gray;" href="#full-flow">Full flow</a>
101<br><span style="margin-right:40px;"></span>
102    <a style="color:gray;" href="#conclusions">Conclusions</a></p>
103
104<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>
105
106<h3>The main idea</h3>
107
108<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>
109
110<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>
111
112<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>
113
114<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>
115
116<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.
117Ethereum 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>
118
119<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>
120
121<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>
122
123<h3>Preliminaries</h3>
124
125<p><strong>Pairing</strong><br>
126We 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>
127
128<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>
129<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>
130
131<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>
132
133<p>Then, the bilinearity property tells us that</p>
134<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>
135<p><span class="math display">\[[x]_1 = x \cdot G \in \mathbb{G}_1\newline
136[x]_2 = x \cdot H \in \mathbb{G}_2\]</span></p><p>So, our previous bilinearity example would look like</p>
137<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>
138
139<p><strong>Code</strong><br>
140For 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>
141
142<h3>Participant contribution</h3>
143
144<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>
145
146<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>
147
148<p>Each participant will obtain the previous-participant generated SRS, which is formed by</p>
149<p><span class="math display">\[\{ [\tau^0]_1, [\tau^1]_1, [\tau^2]_2, \ldots, [\tau^{n-1}]_1 \},\\
150\{ [\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>
151<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>
152
153<p>Then the participant proceeds to update the reference string (SRS), by multiplying each element by <span class="math inline">\(p^i\)</span>:</p>
154<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>
155<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>
156<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>
157<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 \},\\
158\{ [(\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>
159
160<p><br><br>
161We can express the previous logic as follows:</p>
162
163<pre><code class="language-python">def compute_contribution(new_tau, prev_srs):
164    g1s = [None] * len(prev_srs[0])
165    g2s = [None] * len(prev_srs[1])
166    srs = [g1s, g2s]
167    Q = e.r
168
169    # compute [τ'⁰]₁, [τ'¹]₁, [τ'²]₁, ..., [τ'ⁿ⁻¹]₁, where n = len(prev_srs.G1s)
170    for i in range(0, len(prev_srs[0])):
171        srs[0][i] = (new_tau^i) * prev_srs[0][i]
172    
173    # compute [τ'⁰]₂, [τ'¹]₂, [τ'²]₂, ..., [τ'ⁿ⁻¹]₂, where n = len(prev_srs.G2s)
174    for i in range(0, len(prev_srs[1])):
175        srs[1][i] = (new_tau^i) * prev_srs[1][i]
176
177    return srs
178</code></pre>
179
180<h3>Proof of correct computation</h3>
181
182<p>The participant will compute the proof, which consists of</p>
183<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>
184
185<p>In the next section we will see how this is used to verify the contribution correct computation.</p>
186
187<p><br>
188We implement this logic as follows:</p>
189
190<pre><code class="language-python">def generate_proof(tau, prev_srs, new_srs):
191    # g_1^{tau'} = g_1^{p * tau} = SRS_G1s[1] * p
192    g1_ptau = prev_srs[0][1] * tau
193    # g_2^{p}
194    g2_p = tau * e.G2
195    return [g1_ptau, g2_p]
196</code></pre>
197
198<h3>Contribution verification</h3>
199
200<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>
201
202<p>Following the powers of tau structure means that</p>
203<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>
204<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>
205
206<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>
207
208<ol>
209<li><p>Check that elements of the new SRS are non-empty, non-zero and in the correct prime order subgroups.</p></li>
210
211<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>
212
213<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>
214
215<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>
216<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>
217<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>
218<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>
219
220<li><p>Check if the new SRS follows the powers of tau structure:</p>
221<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>
222<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>
223
224<p>And the same for</p>
225<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>
226
227<p>With this check, we&rsquo;re ensuring that each power of tau of the SRS is consistent with the previous one.</p></li>
228</ol>
229
230<p><br><br>
231The complete verification function would look like</p>
232
233<pre><code class="language-python">def verify(prev_srs, new_srs, proof):
234    # 1. check that elements of the newSRS are valid points
235    for i in range(0, len(new_srs[0])-1):
236        assert new_srs[0][i] != None
237        assert new_srs[0][i] != e.E1(0)
238	assert new_srs[0][i] in e.E1
239    for i in range(0, len(new_srs[1])-1):
240        assert new_srs[1][i] != None
241        assert new_srs[1][i] != e.E1(0)
242	assert new_srs[1][i] in e.E2
243
244    # 2. check proof.G1PTau == newSRS.G1Powers[1]
245    assert proof[0] == new_srs[0][1]
246
247    # 3. check newSRS.G1s[1] (g₁^τ'), is correctly related to prev_srs.G1s[1] (g₁^τ)
248	#   e([τ]₁, [p]₂) == e([τ']₁, [1]₂)
249    assert e.pair(prev_srs[0][1], proof[1]) == e.pair(new_srs[0][1], e.G2)
250
251    # 4. check newSRS following the powers of tau structure
252    # i) e([τ'ⁱ]₁, [τ']₂) == e([τ'ⁱ⁺¹]₁, [1]₂), for i ∈ [1, n−1]
253    for i in range(0, len(new_srs[0])-1):
254        assert e.pair(new_srs[0][i], new_srs[1][1]) == e.pair(new_srs[0][i+1], e.G2)
255
256    # ii) e([τ']₁, [τ'ʲ]₂) == e([1]₁, [τ'ʲ⁺¹]₂), for j ∈ [1, m−1]
257    for i in range(0, len(new_srs[1])-1):
258        assert e.pair(new_srs[0][1], new_srs[1][i]) == e.pair(e.G1, new_srs[1][i+1])
259</code></pre>
260
261<h3>Full flow</h3>
262
263<p>Now that we have the three methods (<em>compute_contribution, generate_proof, verify</em>), it&rsquo;s a matter of using them.</p>
264
265<p>First let&rsquo;s add a couple of helpers to our code:</p>
266
267<pre><code class="language-python"># here we import the BLS12-381 pairing machinery
268load(&quot;bls12-381.sage&quot;) # file from https://github.com/arnaucube/math/blob/master/bls12-381.sage
269e = Pairing()
270
271# this method generates a SRS filled by the generator points of G1 &amp; G2
272def new_empty_SRS(nG1, nG2):
273    g1s = [None] * nG1
274    g2s = [None] * nG2
275    for i in range(0, nG1):
276        g1s[i] = e.G1
277    for i in range(0, nG2):
278        g2s[i] = e.G2
279
280    return [g1s, g2s]
281</code></pre>
282
283<p>Let&rsquo;s do the flow:</p>
284
285<pre><code class="language-python"># generate a fake previous-SRS
286(prev_srs) = new_empty_SRS(5, 3)
287
288# set a random value to be used for our tau
289random = 12345 # this would be a random value
290tau = e.F1(random)
291
292# compute our contribution, from the previous SRS and our tau
293new_srs = compute_contribution(tau, prev_srs)
294
295# generate a proof of correct computation of our contribution
296proof = generate_proof(tau, prev_srs, new_srs)
297
298# verify the proof for the given prev_srs and the new_srs
299verify(prev_srs, new_srs, proof)
300</code></pre>
301
302<h2>Conclusions</h2>
303
304<p>As we&rsquo;ve seen, we can prove and verify the correct computation of the new SRS with few operations.</p>
305
306<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>
307
308<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).
309There 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.
310<br><br></p>
311
312<p><a href="https://github.com/arnaucube/eth-kzg-ceremony-alt" target="_blank" title="https://github.com/arnaucube/eth-kzg-ceremony-alt">
313<img src="img/posts/powersoftau/kzg-ceremony-screenshot.png" style="width:100%;" />
314<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>
315</a></p>
316
317<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>
318
319<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.
320So 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>
321
322<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>
323
324    </div>
325
326    <footer style="text-align:center; margin-top:100px;margin-bottom:50px;">
327      <div class="container">
328        <br>
329        <a href="/blog">Go to main</a>
330        <br><br>
331        <div class="row">
332          <ul class="list-inline">
333            <li><a href="https://twitter.com/arnaucube"
334                   style="color:gray;text-decoration:none;"
335                   target="_blank">twitter.com/arnaucube</a>
336            </li>
337            <li><a href="https://github.com/arnaucube"
338                   style="color:gray;text-decoration:none;"
339                   target="_blank">github.com/arnaucube</a>
340            </li>
341          </ul>
342        </div>
343        <div class="row" style="display:inline-block;">
344          Blog made with <a href="http://github.com/arnaucube/blogo/"
345                            target="_blank" style="color: gray;text-decoration:none;">Blogo</a>
346        </div>
347      </div>
348    </footer>
349
350    <script>
351    </script>
352    <script src="js/external-links.js"></script>
353    <script>hljs.initHighlightingOnLoad();</script>
354    <script defer src="js/katex/katex.min.js"></script>
355    <script defer src="js/katex/auto-render.min.js"></script>
356    <script>
357      document.addEventListener("DOMContentLoaded", function() {
358        renderMathInElement(document.body, {
359          displayMode: false,
360          // customised options
361          // • auto-render specific keys, e.g.:
362          delimiters: [
363            {left: '$$', right: '$$', display: true},
364            {left: '$', right: '$', display: false},
365            {left: "\\[", right: "\\]", display: true},
366            {left: "\\(", right: "\\)", display: false},
367            {left: "\\begin{equation}", right: "\\end{equation}", display: true}
368          ],
369          // • rendering keys, e.g.:
370          throwOnError : true
371        });
372      });
373
374      ///
375      let theme = localStorage.getItem("theme");
376      if ((theme === "light-theme")||(theme==null)) {
377          theme = "light-theme";
378          document.getElementById("themeSwitcher").checked = false;
379      } else if (theme === "dark-theme") {
380          theme = "dark-theme";
381          document.getElementById("themeSwitcher").checked = true;
382      }
383      document.body.className = theme;
384      localStorage.setItem("theme", theme);
385
386      function switchTheme() {
387        theme = localStorage.getItem("theme");
388        if (theme === "light-theme") {
389          theme = "dark-theme";
390          document.getElementById("themeSwitcher").checked = true;
391        } else {
392          theme = "light-theme";
393          document.getElementById("themeSwitcher").checked = false;
394        }
395        document.body.className = theme;
396        localStorage.setItem("theme", theme);
397
398        console.log(theme);
399      }
400    </script>
401    <script>
402    function tagLinks(tagName) {
403      var tags = document.getElementsByTagName(tagName);
404      for (var i=0, hElem; hElem =  tags[i]; i++) {
405        if (hElem.parentNode.className=="row postThumb") {
406          continue;
407        }
408        hElem.id = hElem.innerHTML.toLowerCase().replace(" ", "-");
409        hElem.innerHTML = "<a style='color:black!important;' href='#"+hElem.id+"'>"+hElem.innerHTML+"</a>";
410      }
411    }
412    tagLinks("h2");
413    tagLinks("h3");
414    tagLinks("h4");
415    tagLinks("h5");
416    </script>
417    <script>
418function generateTOC(tocContainerId = "toc") {
419    const tocContainer = document.getElementById(tocContainerId);
420    if (!tocContainer) return;
421
422    const headings = document.querySelectorAll("h2, h3, h4, h5, h6");
423    if (!headings.length) return;
424
425    // Generate IDs if missing
426    headings.forEach((heading, index) => {
427        if (!heading.id) {
428            heading.id =
429                heading.textContent
430                    .trim()
431                    .toLowerCase()
432                    .replace(/[^\w\s-]/g, "")
433                    .replace(/\s+/g, "-") +
434                "-" +
435                index;
436        }
437    });
438
439    const toc = document.createElement("ul");
440    let currentLevel = 1;
441    let currentList = toc;
442    const stack = [toc];
443
444    headings.forEach((heading) => {
445        const level = parseInt(heading.tagName.substring(1), 10);
446
447        const li = document.createElement("li");
448        const a = document.createElement("a");
449
450        a.href = "#" + heading.id;
451        a.textContent = heading.textContent;
452
453        li.appendChild(a);
454
455        if (level > currentLevel) {
456            for (let i = currentLevel; i < level; i++) {
457                const nestedList = document.createElement("ul");
458
459                const lastLi =
460                    currentList.lastElementChild ||
461                    currentList.appendChild(document.createElement("ul"));
462
463                lastLi.appendChild(nestedList);
464
465                stack.push(nestedList);
466                currentList = nestedList;
467            }
468        } else if (level < currentLevel) {
469            for (let i = currentLevel; i > level; i--) {
470                stack.pop();
471            }
472            currentList = stack[stack.length - 1];
473        }
474
475        currentList.appendChild(li);
476        currentLevel = level;
477    });
478
479    tocContainer.innerHTML = "";
480    tocContainer.appendChild(toc);
481}
482
483document.addEventListener("DOMContentLoaded", () => {
484    generateTOC();
485});
486    </script>
487    <script src="js/mermaid.min.js"></script>
488
489  </body>
490</html>
491