├── .gitignore
├── LICENSE
├── README.md
├── part1.ipynb
├── part2.ipynb
├── part3.ipynb
├── part4.ipynb
├── rust-toolchain
└── stark101
├── Cargo.toml
└── src
├── channel.rs
├── field.rs
├── lib.rs
├── main.rs
├── merkle_tree.rs
├── parts.rs
└── polynomial.rs
/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | stark101/target/
4 |
5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
7 | stark101/Cargo.lock
8 |
9 | # These are backup files generated by rustfmt
10 | **/*.rs.bk
11 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Lambdaclass
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # STARK101-rs 🦀
2 |
3 | ## About
4 |
5 | This repository is based on the [STARK 101](https://github.com/starkware-industries/stark101) workshop, originally written in Python.
6 |
7 | A Rust tutorial for a basic STARK (**S**calable **T**ransparent **AR**gument of **K**nowledge) protocol
8 | to prove the calculation of a Fibonacci-Square sequence, as designed for StarkWare
9 | Sessions, and authored by the [StarkWare](https://starkware.co) team.
10 |
11 | Note that it was written assuming that the user has reviewed and understood the presentations at the
12 | beginning of each part.
13 |
14 | ## Setup
15 |
16 | In order to follow this workshop you need:
17 | - Have a working installation of Rust and Jupyter
18 | - Install evcxr_jupyter
19 | > cargo install evcxr_jupyter
20 | - Run the following command to register the Rust kernel:
21 | > evcxr_jupyter --install
22 | - Run Jupyter
23 | > jupyter lab
24 |
25 |
26 | ## Math Background
27 |
28 | During the tutorial you’ll generate a STARK proof for the 1023rd element of the
29 | FibonacciSq sequence over a finite field. In this section, we explain what this last sentence means.
30 |
31 | ### Finite Fields
32 |
33 | In the tutorial we will work with a finite field of prime size. This means we take a prime number
34 | _p_, and then work with integers in the domain {0, 1, 2, …, _p_ – 1}. The idea is that we can treat
35 | this set of integers in the same way we treat real numbers: we can add them (but we need to take the
36 | result modulo _p_, so that it will fall back in the set), subtract them, multiply them and divide
37 | them. You can even define polynomials such as _f_ ( _x_ ) = _a_+ _bx_2 where the
38 | coefficients _a_,_b_ and the input _x_ are all numbers in this finite set. Since the addition and
39 | multiplication are done modulo _p_, the output _f _ ( _x_ ) will also be in the finite set. One
40 | interesting thing to note about finite fields, which is different from real numbers, is that there
41 | is always an element, _g_, called the generator (in fact there is more than one), for which the
42 | sequence 1, _g_, _g_2, _g_3, _g_4, ... , _g_p-2 (whose
43 | length is _p_ - 1 ) covers all the numbers in the set but 0 (modulo _p_, of course). Such a
44 | geometric sequence is called a cyclic group. We will supply you with python classes that implement
45 | these things so you don’t have to be familiar with how these are implemented (though the algorithm
46 | for division in a finite field is not that trivial).
47 |
48 | ### FibonacciSq
49 |
50 | For the tutorial we define a sequence that resembles the well known Fibonacci sequence. In this
51 | sequence any element is the sum of squares of the two previous elements. Thus the first elements
52 | are:
53 |
54 | 1, 1, 2, 5, 29, 866, ...
55 |
56 | All the elements of the sequence will be from the finite field (which means that both squaring and
57 | addition is computed modulo p).
58 |
59 | ### STARK Proof
60 |
61 | We will create a proof for the claim “The 1023rd element of the FibonacciSq sequence is
62 | …”. By “proof” we don’t mean a mathematical proof with logical deductions. Instead, we mean some
63 | data which can convince whomever reads it that the claim is correct. To make it more formal we
64 | define two entities: **Prover** and **Verifier**. The Prover generates this data (the proof). The
65 | Verifier gets this data and checks for its validity. The requirement is that if the claim is false,
66 | the Prover will not be able to generate a valid proof (even if it deviates from the protocol).
67 |
68 | STARK is a specific protocol which describes the structure of such proof and defines what the Prover
69 | and Verifier have to do.
70 |
71 | ### Some Other Things You Should Know
72 |
73 | We recommend you take a look at our [STARK math blog
74 | posts](https://medium.com/starkware/tagged/stark-math) (Arithmetization
75 | [I](https://medium.com/starkware/arithmetization-i-15c046390862) &
76 | [II](https://medium.com/starkware/arithmetization-ii-403c3b3f4355) specifically). You don’t need to
77 | read them thoroughly before running through the tutorial, but it can give you better context on what
78 | things you can create proofs for, and what a STARK proof looks like. You should definitely give them
79 | a read after you have completed this tutorial in full.
80 |
81 | ### Division of Polynomials
82 |
83 | For every two polynomials _f_ ( _x_ ) and _g_ ( _x_ ), there exist two polynomials _q_ ( _x_ ) and
84 | _r_ ( _x_) called the quotient and remainder of the division _f_ ( _x_ ) by _g_ ( _x_ ). They
85 | satisfy _f_ ( _x_ ) = _g_ ( _x_ ) \* _q_ ( _x_ ) + _r_ ( _x_ ) and the degree of _r_ ( _x_ ) is
86 | smaller than the degree of _g_ ( _x_ ).
87 |
88 | For example, if _f_ ( _x_ ) = _x_3 + _x_ + 1 and _g_ ( _x_ ) = _x_2 + 1 then
89 | _q_ ( _x_ ) = _x_ and _r_ ( _x_ ) = 1. Indeed, _x_3 + _x_ + 1 = ( _x_2 + 1 )
90 | \* _x_ + 1.
91 |
92 | ### Roots of Polynomials
93 |
94 | When a polynomial satisfies _f_ (_a_) = 0 for some specific value a (we say that _a_ is a root of _f_
95 | ), we don’t have remainder (_r_ ( _x_ ) = 0) when dividing it by (_x_ - _a_) so we can write _f_ (
96 | _x_ ) = (_x_ - _a_) \* _q_ ( _x_ ), and deg( _q_ ) = deg( _f_ ) - 1. A similar fact is true for _k_
97 | roots. Namely, if _a__i_ is a root of _f_ for all _i_ = 1, 2, …, _k_, then there exists a
98 | polynomial _q_ of degree deg(_f_) - _k_ for which _f_ ( _x_ ) = ( _x_ - _a_1 )( _x_ -
99 | _a_2 ) … ( _x_ - _a__k_ ) \* _q_ ( _x_ ) .
100 |
101 | ### Want to Know More?
102 |
103 | 1. Nigel Smart’s [“Cryptography Made Simple”](https://www.cs.umd.edu/~waa/414-F11/IntroToCrypto.pdf)
104 | – Chapter 1.1: Modular Arithmetic.
105 |
106 | 2. Arora and Barak’s [“Computational Complexity: A Modern
107 | Approach”](http://theory.cs.princeton.edu/complexity/book.pdf) – Appendix: Mathematical
108 | Background, sections A.4 (Finite fields and Groups) and A.6 (Polynomials).
109 |
--------------------------------------------------------------------------------
/part1.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "*Copyright 2019 StarkWare Industries Ltd.
Licensed under the Apache License, Version 2.0 (the \"License\"). You may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.starkware.co/open-source-license/
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {
13 | "tags": []
14 | },
15 | "source": [
16 | "# Part 1: Trace and Low-Degree Extension\n",
17 | "\n",
18 | "- [Video Lecture (youtube)](https://www.youtube.com/watch?v=Y0uJz9VL3Fo)\n",
19 | "- [Slides (PDF)](https://starkware.co/wp-content/uploads/2021/12/STARK101-Part1.pdf)\n",
20 | "\n",
21 | "Today we will develop a STARK prover for the FibonacciSq sequence over a finite field.\n",
22 | "The FibonacciSq sequence is defined by the recurrence relation $a_{n+2} = a_{n+1} ^2 + a_n ^2$.\n",
23 | "
By the end of the day, your code will produce a *STARK* proof attesting to the following statement:
**I know a field element $X\\in \\mathbb{F}$ such that the 1023rd element of the FibonacciSq sequence starting with $1, X$ is $2338775057$**.\n",
24 | "
\n",
25 | "## The Basics\n",
26 | "### FieldElement class\n",
27 | "We use our `FieldElement` struct to represent field elements.
You can construct values of type `FieldElement` from integers, and then add, multiply, divide, get inverse, and so on.\n",
28 | "The underlying field of this class is $\\mathbb{F}_{3221225473}$ ($3221225473 = 3 \\cdot 2^{30} + 1$), so all operations are done modulo 3221225473.\n",
29 | "
\n",
30 | "Try it by running the following cell (shift + enter):"
31 | ]
32 | },
33 | {
34 | "cell_type": "code",
35 | "execution_count": 276,
36 | "metadata": {},
37 | "outputs": [],
38 | "source": [
39 | ":dep stark101-rs = { path = \"stark101\" }\n",
40 | ":dep sha256 = \"1.1.2\""
41 | ]
42 | },
43 | {
44 | "cell_type": "code",
45 | "execution_count": 277,
46 | "metadata": {
47 | "scrolled": true
48 | },
49 | "outputs": [
50 | {
51 | "name": "stdout",
52 | "output_type": "stream",
53 | "text": [
54 | "The result is: FieldElement(9)\n"
55 | ]
56 | }
57 | ],
58 | "source": [
59 | "use stark101_rs::field::*;\n",
60 | "println!(\"The result is: {:?}\", FieldElement::new(3221225472) + FieldElement::new(10));"
61 | ]
62 | },
63 | {
64 | "cell_type": "markdown",
65 | "metadata": {},
66 | "source": [
67 | "## FibonacciSq Trace\n",
68 | "\n",
69 | "To start, let's construct a vector `a` of length 1023, whose first two elements will be FieldElement objects representing 1 and 3141592, respectively. The next 1021 elements will be the FibonacciSq sequence induced by these two elements. `a` is called the trace of FibonacciSq, or, when the context is clear, the trace.
\n",
70 | "Correct the code below to fill `a`:"
71 | ]
72 | },
73 | {
74 | "cell_type": "code",
75 | "execution_count": 278,
76 | "metadata": {},
77 | "outputs": [
78 | {
79 | "name": "stderr",
80 | "output_type": "stream",
81 | "text": [
82 | "thread '' panicked at 'not yet implemented: Put your code here', src/lib.rs:160:1\n",
83 | "stack backtrace:\n",
84 | " 0: _rust_begin_unwind\n",
85 | " 1: core::panicking::panic_fmt\n",
86 | " 2: \n",
87 | " 3: \n",
88 | " 4: evcxr::runtime::Runtime::run_loop\n",
89 | " 5: evcxr::runtime::runtime_hook\n",
90 | " 6: evcxr_jupyter::main\n",
91 | "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
92 | ]
93 | }
94 | ],
95 | "source": [
96 | "let mut a = vec![FieldElement::new(1), FieldElement::new(3141592)];\n",
97 | "todo!(\"Put your code here\");"
98 | ]
99 | },
100 | {
101 | "cell_type": "markdown",
102 | "metadata": {},
103 | "source": [
104 | "Solution (click to the ... to unhide):"
105 | ]
106 | },
107 | {
108 | "cell_type": "code",
109 | "execution_count": 279,
110 | "metadata": {
111 | "tags": []
112 | },
113 | "outputs": [
114 | {
115 | "data": {
116 | "text/plain": [
117 | "()"
118 | ]
119 | },
120 | "execution_count": 279,
121 | "metadata": {},
122 | "output_type": "execute_result"
123 | }
124 | ],
125 | "source": [
126 | "let mut a = vec![FieldElement::new(1), FieldElement::new(3141592)];\n",
127 | "let mut n = 2usize;\n",
128 | "while a.len() < 1023 {\n",
129 | " a.push(a[n-2] * a[n-2] + a[n-1] * a[n-1]);\n",
130 | " n += 1;\n",
131 | "}"
132 | ]
133 | },
134 | {
135 | "cell_type": "markdown",
136 | "metadata": {},
137 | "source": [
138 | "### Test Your Code\n",
139 | "Run the next cell to test that you have filled `a` correctly.
Note that this is in fact a **verifier**, albeit very naive and non-succinct one, as it goes over the sequence, element by element, making sure it is correct."
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 280,
145 | "metadata": {},
146 | "outputs": [
147 | {
148 | "name": "stdout",
149 | "output_type": "stream",
150 | "text": [
151 | "Success!\n"
152 | ]
153 | }
154 | ],
155 | "source": [
156 | "assert_eq!(a.len(), 1023, \"The trace must consist of exactly 1023 elements.\");\n",
157 | "assert_eq!(a[0], FieldElement::new(1), \"The first element in the trace must be the unit element.\");\n",
158 | "for i in 2..1023 {\n",
159 | " assert_eq!(a[i], a[i - 1] * a[i - 1] + a[i - 2] * a[i - 2], \"The FibonacciSq recursion rule does not apply for index {i}\");\n",
160 | "}\n",
161 | "assert_eq!(a[1022], FieldElement::new(2338775057), \"Wrong last element!\");\n",
162 | "println!(\"Success!\");"
163 | ]
164 | },
165 | {
166 | "cell_type": "markdown",
167 | "metadata": {},
168 | "source": [
169 | "## Thinking of Polynomials\n",
170 | "We now want to think of the sequence as the evaluation of some, yet unknown, polynomial $f$ of degree 1022 (due to the Unisolvence Theorem).\n",
171 | "We will choose the domain to be some subgroup $G \\subseteq \\mathbb{F}^\\times$ of size 1024, for reasons that will become clear later.\n",
172 | "\n",
173 | "(Recall that $\\mathbb{F}^\\times$ denotes the multiplicative group of $\\mathbb{F}$, which we get from $\\mathbb{F}$ by omitting the zero element with the induced multiplication from the field. A subgroup of size 1024 exists because $\\mathbb{F}^\\times$ is a cyclic group of size $3\\cdot 2^{30}$, so it contains a subgroup of size $2^i$ for any $0 \\leq i \\leq 30$).\n",
174 | "### Find a Group of Size 1024\n",
175 | "If we find an element $g \\in \\mathbb{F}$ whose (multiplicative) order is 1024, then $g$ will generate such a group.\n",
176 | "The struct `FieldElement` provides a method `generator()` which returns an element that generates $\\mathbb{F}^\\times$ (whose order is $|\\mathbb{F}^\\times|$).\n",
177 | "1. Use it to obtain a generator $g$ for $G$.\n",
178 | "2. Create a vec called `G` with all the elements of $G$, such that $G[i] := g^i$.\n",
179 | "\n",
180 | "*Hint: When $k$ divides $|\\mathbb{F}^\\times|$, $g^k$ generates a group of size $\\frac {|\\mathbb{F}^\\times|}{k}$, and the n-th power of some `FieldElement` $x$ can be computed by calling `x ** n `.*\n",
181 | "\n"
182 | ]
183 | },
184 | {
185 | "cell_type": "code",
186 | "execution_count": 281,
187 | "metadata": {},
188 | "outputs": [],
189 | "source": [
190 | "// Change the following line so that g will generate a group of size 1024\n",
191 | "let g = FieldElement::generator();\n",
192 | "// Fill G with the elements of G such that G[i] := g ** i\n",
193 | "let G: Vec = vec![]; "
194 | ]
195 | },
196 | {
197 | "cell_type": "markdown",
198 | "metadata": {},
199 | "source": [
200 | "Solution:"
201 | ]
202 | },
203 | {
204 | "cell_type": "code",
205 | "execution_count": 282,
206 | "metadata": {
207 | "tags": []
208 | },
209 | "outputs": [],
210 | "source": [
211 | "let g = FieldElement::generator().pow(3 * 2usize.pow(20));\n",
212 | "let G: Vec = (0..1024).into_iter().map(|i| g.pow(i)).collect();"
213 | ]
214 | },
215 | {
216 | "cell_type": "markdown",
217 | "metadata": {},
218 | "source": [
219 | "Run the next cell to test your code. "
220 | ]
221 | },
222 | {
223 | "cell_type": "code",
224 | "execution_count": 283,
225 | "metadata": {},
226 | "outputs": [
227 | {
228 | "name": "stdout",
229 | "output_type": "stream",
230 | "text": [
231 | "Success!\n"
232 | ]
233 | },
234 | {
235 | "data": {
236 | "text/plain": [
237 | "()"
238 | ]
239 | },
240 | "execution_count": 283,
241 | "metadata": {},
242 | "output_type": "execute_result"
243 | }
244 | ],
245 | "source": [
246 | "// Checks that g and G are correct.\n",
247 | "assert!(g.is_order(1024), \"The generator g is of wrong order.\");\n",
248 | "let mut b = FieldElement::one();\n",
249 | "for i in 0..1023 {\n",
250 | " assert_eq!(b, G[i], \"The i-th place in G is not equal to the i-th power of g.\");\n",
251 | " b = b * g;\n",
252 | " let wrong_order = i + 1;\n",
253 | " assert!(b != FieldElement::one(), \"g is of order {wrong_order}\");\n",
254 | "} \n",
255 | "if b * g == FieldElement::one() {\n",
256 | " println!(\"Success!\");\n",
257 | "} else {\n",
258 | " println!(\"g is of order > 1024\");\n",
259 | "}"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "### Polynomial class\n",
267 | "We provide you with a struct called `Polynomial`. The simplest way to construct a `Polynomial` is by using the function **x()** which represents the formal variable $x$:"
268 | ]
269 | },
270 | {
271 | "cell_type": "code",
272 | "execution_count": 284,
273 | "metadata": {},
274 | "outputs": [
275 | {
276 | "name": "stdout",
277 | "output_type": "stream",
278 | "text": [
279 | "FieldElement(9)\n"
280 | ]
281 | }
282 | ],
283 | "source": [
284 | "use stark101_rs::polynomial::*;\n",
285 | "// The polynomial 2x^2 + 1.\n",
286 | "let p: Polynomial = 2*x().pow(2) + 1;\n",
287 | "// Evaluate p at 2:\n",
288 | "println!(\"{:?}\", p(2));"
289 | ]
290 | },
291 | {
292 | "cell_type": "markdown",
293 | "metadata": {},
294 | "source": [
295 | "### Interpolating a Polynomial\n",
296 | "Our `Polynomial` datatype provides a Lagrange interpolation method, whose arguments are:\n",
297 | "* x_values: x-values of G that the polynomial's values for them is known. &[FieldElement]\n",
298 | "* y_values: the corresponding y-values. &[FieldElement]\n",
299 | "\n",
300 | "It returns the unique `Polynomial` of degree < `x_values.len()` instance that evaluates to `y_values[i]` on `x_values[i]` for all i."
301 | ]
302 | },
303 | {
304 | "cell_type": "markdown",
305 | "metadata": {},
306 | "source": [
307 | "Suppose that `a` contains the values of some polynomial over `G` (except for `G[-1]`, since `a` is one element shorter).\n",
308 | "Use `Polynomial::interpolate()` to get `f` and get its value at `FieldElement::new(2)`. "
309 | ]
310 | },
311 | {
312 | "cell_type": "code",
313 | "execution_count": 285,
314 | "metadata": {},
315 | "outputs": [
316 | {
317 | "name": "stderr",
318 | "output_type": "stream",
319 | "text": [
320 | "thread '' panicked at 'not yet implemented: Put your code here.', src/lib.rs:162:1\n",
321 | "stack backtrace:\n",
322 | " 0: _rust_begin_unwind\n",
323 | " 1: core::panicking::panic_fmt\n",
324 | " 2: \n",
325 | " 3: \n",
326 | " 4: evcxr::runtime::Runtime::run_loop\n",
327 | " 5: evcxr::runtime::runtime_hook\n",
328 | " 6: evcxr_jupyter::main\n",
329 | "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
330 | ]
331 | }
332 | ],
333 | "source": [
334 | "// Fix the following so that you create a variable called v that will contain the value of f at FieldElement(2)\n",
335 | "// Note that Polynomial::interpolate may take up to a minute to run.\n",
336 | "todo!(\"Put your code here.\");"
337 | ]
338 | },
339 | {
340 | "cell_type": "markdown",
341 | "metadata": {},
342 | "source": [
343 | "Solution:"
344 | ]
345 | },
346 | {
347 | "cell_type": "code",
348 | "execution_count": 286,
349 | "metadata": {
350 | "tags": []
351 | },
352 | "outputs": [],
353 | "source": [
354 | "let xs: Vec = G.into_iter().rev().skip(1).rev().collect();\n",
355 | "let f: Polynomial = Polynomial::interpolate(&xs, &a);\n",
356 | "let v = f(2);"
357 | ]
358 | },
359 | {
360 | "cell_type": "markdown",
361 | "metadata": {},
362 | "source": [
363 | "Run test:"
364 | ]
365 | },
366 | {
367 | "cell_type": "code",
368 | "execution_count": 287,
369 | "metadata": {},
370 | "outputs": [
371 | {
372 | "name": "stdout",
373 | "output_type": "stream",
374 | "text": [
375 | "Success!\n"
376 | ]
377 | }
378 | ],
379 | "source": [
380 | "assert_eq!(v, FieldElement::new(1302089273));\n",
381 | "println!(\"Success!\");"
382 | ]
383 | },
384 | {
385 | "cell_type": "markdown",
386 | "metadata": {},
387 | "source": [
388 | "## Evaluating on a Larger Domain\n",
389 | "The trace, viewed as evaluations of a polynomial $f$ on $G$, can now be extended by evaluating $f$ over a larger domain, thereby creating a **Reed-Solomon error correction code**.\n",
390 | "\n",
391 | "### Cosets\n",
392 | "To that end, we must decide on a larger domain on which $f$ will be evaluated. \n",
393 | "We will work with a domain that is 8 times larger than $G$.
A natural choice for such a domain is to take some group $H$ of size 8192 (which exists because 8192 divides $|\\mathbb{F}^\\times|$), and shift it by the generator of $\\mathbb{F}^\\times$, thereby obtaining a [coset](https://en.wikipedia.org/wiki/Coset) of $H$.\n",
394 | "\n",
395 | "Create a vec called `H` of the elements of $H$, and multiply each of them by the generator of $\\mathbb{F}^\\times$ to obtain a vec called `eval_domain`. In other words, eval_domain = $\\{w\\cdot h^i | 0 \\leq i <8192 \\}$ for $h$ the generator of $H$ and $w$ the generator of $\\mathbb{F}^\\times$.\n",
396 | "\n",
397 | "Hint: You already know how to obtain $H$ - similarly to the way we got $G$ a few minutes ago.\n"
398 | ]
399 | },
400 | {
401 | "cell_type": "code",
402 | "execution_count": 288,
403 | "metadata": {},
404 | "outputs": [
405 | {
406 | "name": "stderr",
407 | "output_type": "stream",
408 | "text": [
409 | "thread '' panicked at 'not yet implemented', src/lib.rs:160:23\n",
410 | "stack backtrace:\n",
411 | " 0: _rust_begin_unwind\n",
412 | " 1: core::panicking::panic_fmt\n",
413 | " 2: core::panicking::panic\n",
414 | " 3: \n",
415 | " 4: \n",
416 | " 5: evcxr::runtime::Runtime::run_loop\n",
417 | " 6: evcxr::runtime::runtime_hook\n",
418 | " 7: evcxr_jupyter::main\n",
419 | "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
420 | ]
421 | }
422 | ],
423 | "source": [
424 | "// Fix the following, make sure that the the element of H are powers of its generator (let's call it h) in \n",
425 | "// order, that is - H[0] will be the unit (i.e 1), H[1] will be h (H's generator), H[2] will be H's\n",
426 | "// generator squared (h^2), etc.\n",
427 | "let h: FieldElement = todo!();\n",
428 | "let H: Vec = todo!();\n",
429 | "let eval_domain: Vec = todo!();"
430 | ]
431 | },
432 | {
433 | "cell_type": "markdown",
434 | "metadata": {},
435 | "source": [
436 | "Solution:"
437 | ]
438 | },
439 | {
440 | "cell_type": "code",
441 | "execution_count": 289,
442 | "metadata": {
443 | "tags": []
444 | },
445 | "outputs": [],
446 | "source": [
447 | "let w = FieldElement::generator();\n",
448 | "let exp = (2usize.pow(30) * 3) / 8192;\n",
449 | "let h = w.pow(exp);\n",
450 | "let H: Vec = (0..8192).into_iter().map(|i| h.pow(i)).collect(); \n",
451 | "let eval_domain: Vec = H.into_iter().map(|x| w * x).collect();"
452 | ]
453 | },
454 | {
455 | "cell_type": "markdown",
456 | "metadata": {},
457 | "source": [
458 | "Run test:"
459 | ]
460 | },
461 | {
462 | "cell_type": "code",
463 | "execution_count": 290,
464 | "metadata": {
465 | "scrolled": true
466 | },
467 | "outputs": [
468 | {
469 | "name": "stdout",
470 | "output_type": "stream",
471 | "text": [
472 | "Success!\n"
473 | ]
474 | }
475 | ],
476 | "source": [
477 | "let field_generator = FieldElement::generator();\n",
478 | "let w_inverse = w.inverse();\n",
479 | "\n",
480 | "for i in 0..8192 {\n",
481 | " assert_eq!((w_inverse * eval_domain[1]).pow(i) * field_generator, eval_domain[i]);\n",
482 | "}\n",
483 | "println!(\"Success!\");"
484 | ]
485 | },
486 | {
487 | "cell_type": "markdown",
488 | "metadata": {},
489 | "source": [
490 | "### Evaluate on a Coset\n",
491 | "Time to use `interpolate` and `eval` to evaluate over the coset. Note that it is implemented fairely naively in our Rust module, so interpolation may take some seconds.
\n",
492 | "Indeed - interpolating and evaluating the trace polynomial is one of the most computationally-intensive steps in the STARK protocol, even when using more efficient methods (e.g. FFT)."
493 | ]
494 | },
495 | {
496 | "cell_type": "code",
497 | "execution_count": 291,
498 | "metadata": {},
499 | "outputs": [
500 | {
501 | "name": "stderr",
502 | "output_type": "stream",
503 | "text": [
504 | "thread '' panicked at 'not yet implemented', src/lib.rs:162:28\n",
505 | "stack backtrace:\n",
506 | " 0: _rust_begin_unwind\n",
507 | " 1: core::panicking::panic_fmt\n",
508 | " 2: core::panicking::panic\n",
509 | " 3: \n",
510 | " 4: \n",
511 | " 5: evcxr::runtime::Runtime::run_loop\n",
512 | " 6: evcxr::runtime::runtime_hook\n",
513 | " 7: evcxr_jupyter::main\n",
514 | "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
515 | ]
516 | }
517 | ],
518 | "source": [
519 | "// Fill f_eval with the evaluations of f on eval_domain.\n",
520 | "let f_eval: FieldElement = todo!();"
521 | ]
522 | },
523 | {
524 | "cell_type": "markdown",
525 | "metadata": {},
526 | "source": [
527 | "Solution:"
528 | ]
529 | },
530 | {
531 | "cell_type": "code",
532 | "execution_count": 292,
533 | "metadata": {
534 | "tags": []
535 | },
536 | "outputs": [],
537 | "source": [
538 | "let G_values: Vec = (0..1024).into_iter().map(|i| g.pow(i)).collect();;\n",
539 | "let x_values: Vec = G_values.into_iter().rev().skip(1).rev().collect();\n",
540 | "let interpolated_f: Polynomial = Polynomial::interpolate(&x_values, &a);\n",
541 | "let interpolated_f_eval: Vec = eval_domain.into_iter().map(|d| interpolated_f.clone().eval(d)).collect();"
542 | ]
543 | },
544 | {
545 | "cell_type": "markdown",
546 | "metadata": {},
547 | "source": [
548 | "Run test:"
549 | ]
550 | },
551 | {
552 | "cell_type": "code",
553 | "execution_count": 300,
554 | "metadata": {},
555 | "outputs": [
556 | {
557 | "name": "stdout",
558 | "output_type": "stream",
559 | "text": [
560 | "Success!\n"
561 | ]
562 | }
563 | ],
564 | "source": [
565 | "// Test against a precomputed hash.\n",
566 | "use sha256::digest;\n",
567 | "let hashed = digest(format!(\"{:?}\", interpolated_f_eval));\n",
568 | "assert_eq!(\"d78b6a5f70e91dd8fa448f628528434dbfaf3caefab0a26519e1f2d8ac992f23\".to_string(), hashed);\n",
569 | "println!(\"Success!\");"
570 | ]
571 | },
572 | {
573 | "cell_type": "markdown",
574 | "metadata": {},
575 | "source": [
576 | "## Commitments\n",
577 | "We will use [Sha256](https://en.wikipedia.org/wiki/SHA-2)-based [Merkle Trees](https://en.wikipedia.org/wiki/Merkle_tree) as our commitment scheme.\n",
578 | "A simple implementation of it is available to you in the `MerkleTree` class.\n",
579 | "Run the next cell (for the sake of this tutorial, this also serves as a test for correctness of the entire computation so far):"
580 | ]
581 | },
582 | {
583 | "cell_type": "code",
584 | "execution_count": 294,
585 | "metadata": {},
586 | "outputs": [],
587 | "source": [
588 | "//from merkle import MerkleTree\n",
589 | "//f_merkle = MerkleTree(f_eval)\n",
590 | "//assert f_merkle.root == '6c266a104eeaceae93c14ad799ce595ec8c2764359d7ad1b4b7c57a4da52be04'\n",
591 | "//print('Success!')"
592 | ]
593 | },
594 | {
595 | "cell_type": "markdown",
596 | "metadata": {},
597 | "source": [
598 | "## Channel\n",
599 | "Theoretically, a STARK proof system is a protocol for interaction between two parties - a prover and a verifier. In practice, we convert this interactive protocol into a non-interactive proof using the [Fiat-Shamir Heuristic](https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic). In this tutorial you will use the `Channel` class, which implements this transformation. This channel replaces the verifier in the sense that the prover (which you are writing) will send data, and receive random numbers or random `FieldElement` instances.\n",
600 | "\n",
601 | "This simple piece of code instantiates a channel object, sends the root of your Merkle Tree to it. \n",
602 | "Later, the channel object can be called to provide random numbers or random field elements."
603 | ]
604 | },
605 | {
606 | "cell_type": "code",
607 | "execution_count": 295,
608 | "metadata": {},
609 | "outputs": [],
610 | "source": [
611 | "///from channel import Channel\n",
612 | "//channel = Channel()\n",
613 | "//channel.send(f_merkle.root)"
614 | ]
615 | },
616 | {
617 | "cell_type": "markdown",
618 | "metadata": {},
619 | "source": [
620 | "Lastly - you can retrieve the proof-so-far (i.e., everything that was passed in the channel up until a certain point) by printing the member `Channel.proof`."
621 | ]
622 | },
623 | {
624 | "cell_type": "code",
625 | "execution_count": 296,
626 | "metadata": {},
627 | "outputs": [],
628 | "source": [
629 | "//print(channel.proof)"
630 | ]
631 | }
632 | ],
633 | "metadata": {
634 | "kernelspec": {
635 | "display_name": "Rust",
636 | "language": "rust",
637 | "name": "rust"
638 | },
639 | "language_info": {
640 | "codemirror_mode": "rust",
641 | "file_extension": ".rs",
642 | "mimetype": "text/rust",
643 | "name": "Rust",
644 | "pygment_lexer": "rust",
645 | "version": ""
646 | }
647 | },
648 | "nbformat": 4,
649 | "nbformat_minor": 4
650 | }
651 |
--------------------------------------------------------------------------------
/part2.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "*Copyright 2019 StarkWare Industries Ltd.
Licensed under the Apache License, Version 2.0 (the \"License\"). You may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.starkware.co/open-source-license/
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Part 2: Constraints\n",
15 | "\n",
16 | "- [Video Lecture (youtube)](https://www.youtube.com/watch?v=fg3mFPXEYQY)\n",
17 | "- [Slides (PDF)](https://starkware.co/wp-content/uploads/2021/12/STARK101-Part2.pdf)\n",
18 | "\n",
19 | "In this part, we are going to create a set of constraints over the trace `a`.
The constraints will be expressions in the trace's cells that are polynomials (rather than [rational functions](https://en.wikipedia.org/wiki/Rational_function)) if and only if the trace represents a valid computation of the FibonacciSq.
\n",
20 | "
\n",
21 | "We will get there in three steps:\n",
22 | "1. Start by specifying the constraints we care about (the **FibonacciSq constraints**).\n",
23 | "2. Translate the FibonacciSq constraints into **polynomial constraints**.\n",
24 | "3. Translate those into **rational functions** that represent polynomials if and only if the original constraints hold. "
25 | ]
26 | },
27 | {
28 | "cell_type": "markdown",
29 | "metadata": {},
30 | "source": [
31 | "## Step 1 - FibonacciSq Constraints\n",
32 | "For `a` to be a correct trace of a FibonacciSq sequence that proves our claim:\n",
33 | "1. The first element has to be 1, namely $a[0] = 1$.\n",
34 | "2. The last element has to be 2338775057, namely $a[1022] = 2338775057$.\n",
35 | "3. The FibonacciSq rule must apply, that is - for every $i<1021$, $a[i+2]=a[i+1]^2+a[i]^2$."
36 | ]
37 | },
38 | {
39 | "cell_type": "markdown",
40 | "metadata": {},
41 | "source": [
42 | "## Step 2 - Polynomial Constraints\n",
43 | "Recall that `f` is a polynomial over the trace domain, that evaluates exactly to `a` over $G \\setminus \\{g^{1023}\\}$ where $G=\\{g^i : 0\\leq i\\leq 1023\\}$ is the \"small\" group generated by $g$.
\n",
44 | "\n",
45 | "We now rewrite the above three constraints in a form of polynomial constraints over `f`:\n",
46 | "1. $a[0] = 1$ is translated to the polynomial $f(x) - 1$, which evalutes to 0 for $x = g^0$ (note that $g^0$ is $1$).
\n",
47 | "2. $a[1022] = 2338775057$ is translated to the polynomial $f(x) - 2338775057$, which evalutes to 0 for $x = g^{1022}$.
\n",
48 | "3. $a[i+2]=a[i+1]^2+a[i]^2$ for every $i<1021$ is translated to the polynomial $f(g^2 \\cdot x) - (f(g \\cdot x))^2 - (f(x))^2$, which evaluates to 0 for $x \\in G \\backslash \\{g^{1021}, g^{1022}, g^{1023}\\}$.
"
49 | ]
50 | },
51 | {
52 | "cell_type": "markdown",
53 | "metadata": {},
54 | "source": [
55 | "### Hands on\n",
56 | "First, since this is a separate notebook from Part 1, let's run the following piece of code to have all the variables here with their correct values. Note that it may take up to 30 seconds, since it reruns the polynomial interpolation."
57 | ]
58 | },
59 | {
60 | "cell_type": "code",
61 | "execution_count": 141,
62 | "metadata": {},
63 | "outputs": [
64 | {
65 | "name": "stdout",
66 | "output_type": "stream",
67 | "text": [
68 | "Success!\n"
69 | ]
70 | }
71 | ],
72 | "source": [
73 | ":dep stark101-rs = { path = \"stark101\" }\n",
74 | ":dep sha256 = \"1.1.2\"\n",
75 | "use stark101_rs::{field::FieldElement, channel::Channel, polynomial::{Polynomial, x}};\n",
76 | "use stark101_rs::parts::part1();\n",
77 | "\n",
78 | "let (a, g, G, h, H, eval_domain, f, f_eval, f_merkle, channel) = part1();\n",
79 | "println!(\"Success!\");"
80 | ]
81 | },
82 | {
83 | "cell_type": "markdown",
84 | "metadata": {},
85 | "source": [
86 | "You will obtain each of the three constraints as a quotient of two polynomials, making sure the remainder is the zero polynomial. \n",
87 | "
"
88 | ]
89 | },
90 | {
91 | "cell_type": "markdown",
92 | "metadata": {},
93 | "source": [
94 | "## Step 3 - Rational Functions (That are in Fact Polynomials)\n",
95 | "\n",
96 | "Each of the constraints above is represented by a polynomial $u(x)$ that supposedly evaluates to $0$ on certain elements of the group $G$. That is, for some $x_0, \\ldots, x_k \\in G$, we claim that\n",
97 | "\n",
98 | "$$u(x_0) = \\ldots = u(x_k) = 0$$\n",
99 | "\n",
100 | "(note that for the first two constaints, $k=0$ because they only refer to one point and for the third $k=1021$).\n",
101 | "\n",
102 | "This is equivalent to saying that $u(x)$ is divisible, as a polynomial, by all of $\\{(x-x_i)\\}_{i=0}^k$, or, equivalently, by\n",
103 | "\n",
104 | "$$\\prod_{i=0}^k (x-x_i)$$\n",
105 | "\n",
106 | "Therefore, each of the three constraints above can be written as a rational function of the form:\n",
107 | "\n",
108 | "$$\\frac{u(x)}{\\prod_{i=0}^k (x-x_i)}$$\n",
109 | "\n",
110 | "for the corresponding $u(x)$ and $\\{x_i\\}_{i=0}^k$. In this step we will construct these three rational functions and show that they are indeed polynomials."
111 | ]
112 | },
113 | {
114 | "cell_type": "markdown",
115 | "metadata": {},
116 | "source": [
117 | "## The First Constraint:\n",
118 | "\n",
119 | "In the first constraint, $f(x) - 1$ and $\\{x_i\\} = \\{1\\}$.\n",
120 | "\n",
121 | "We will now construct the **polynomial** $p_0(x)=\\frac{f(x) - 1}{x - 1}$, making sure that $f(x) - 1$ is indeed divisible by $(x-1)$."
122 | ]
123 | },
124 | {
125 | "cell_type": "code",
126 | "execution_count": null,
127 | "metadata": {},
128 | "outputs": [],
129 | "source": [
130 | "// First constraint. Construct numer0 and denom0.\n",
131 | "let numer0: Polynomial = todo!();\n",
132 | "let denom0: Polynomial = todo!();"
133 | ]
134 | },
135 | {
136 | "cell_type": "markdown",
137 | "metadata": {},
138 | "source": [
139 | "Solution:"
140 | ]
141 | },
142 | {
143 | "cell_type": "code",
144 | "execution_count": 142,
145 | "metadata": {
146 | "tags": []
147 | },
148 | "outputs": [],
149 | "source": [
150 | "let numer0: Polynomial = f.clone() - FieldElement::one();\n",
151 | "let denom0: Polynomial = x() - FieldElement::one();"
152 | ]
153 | },
154 | {
155 | "cell_type": "markdown",
156 | "metadata": {},
157 | "source": [
158 | "Convince yourself that $f(x) - 1$ vanishes at $x=1$ by making sure that evaluating this polynomial at $1$ yields $0$:"
159 | ]
160 | },
161 | {
162 | "cell_type": "code",
163 | "execution_count": null,
164 | "metadata": {},
165 | "outputs": [],
166 | "source": [
167 | "todo!(\"You should evaluate f(x) - 1 at x = 1\");"
168 | ]
169 | },
170 | {
171 | "cell_type": "markdown",
172 | "metadata": {},
173 | "source": [
174 | "The fact that $f(x) - 1$ has a root at $1$ implies that it is divisible by $(x - 1)$.\n",
175 | "Run the following cell to convince yourself that the remainder of `numer0` modulo `denom0` is $0$, and therefore division indeed yields a polynomial:"
176 | ]
177 | },
178 | {
179 | "cell_type": "code",
180 | "execution_count": 36,
181 | "metadata": {
182 | "scrolled": true
183 | },
184 | "outputs": [
185 | {
186 | "data": {
187 | "text/plain": [
188 | "Polynomial([])"
189 | ]
190 | },
191 | "execution_count": 36,
192 | "metadata": {},
193 | "output_type": "execute_result"
194 | }
195 | ],
196 | "source": [
197 | "numer0.clone() % denom0.clone()"
198 | ]
199 | },
200 | {
201 | "cell_type": "markdown",
202 | "metadata": {},
203 | "source": [
204 | "Run the following cell to construct `p0`, the polynomial representing the first constraint, by dividing `numer0` by `denom0`:"
205 | ]
206 | },
207 | {
208 | "cell_type": "code",
209 | "execution_count": 143,
210 | "metadata": {},
211 | "outputs": [],
212 | "source": [
213 | "let p0: Polynomial = numer0 / denom0;"
214 | ]
215 | },
216 | {
217 | "cell_type": "markdown",
218 | "metadata": {},
219 | "source": [
220 | "Run test:"
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "execution_count": 5,
226 | "metadata": {},
227 | "outputs": [
228 | {
229 | "name": "stdout",
230 | "output_type": "stream",
231 | "text": [
232 | "Success!\n"
233 | ]
234 | }
235 | ],
236 | "source": [
237 | "assert_eq!(p0(2718), 2509888982);\n",
238 | "println!(\"Success!\");"
239 | ]
240 | },
241 | {
242 | "cell_type": "markdown",
243 | "metadata": {},
244 | "source": [
245 | "## The Second Constraint\n",
246 | "\n",
247 | "Construct the polynomial `p1` representing the second constraint, $p_1(x)= \\frac{f(x) - 2338775057}{x - g^{1022}}$, similarly:
"
248 | ]
249 | },
250 | {
251 | "cell_type": "code",
252 | "execution_count": null,
253 | "metadata": {},
254 | "outputs": [],
255 | "source": [
256 | "// Second constraint.\n",
257 | "let p1: Polynomial = todo!();"
258 | ]
259 | },
260 | {
261 | "cell_type": "markdown",
262 | "metadata": {},
263 | "source": [
264 | "Solution:"
265 | ]
266 | },
267 | {
268 | "cell_type": "code",
269 | "execution_count": 144,
270 | "metadata": {
271 | "tags": []
272 | },
273 | "outputs": [],
274 | "source": [
275 | "let numer1: Polynomial = f.clone() - FieldElement::new(2338775057);\n",
276 | "let denom1: Polynomial = x() - g.pow(1022usize);\n",
277 | "let p1: Polynomial = numer1 / denom1.clone();"
278 | ]
279 | },
280 | {
281 | "cell_type": "markdown",
282 | "metadata": {},
283 | "source": [
284 | "Run test:"
285 | ]
286 | },
287 | {
288 | "cell_type": "code",
289 | "execution_count": 83,
290 | "metadata": {},
291 | "outputs": [
292 | {
293 | "name": "stdout",
294 | "output_type": "stream",
295 | "text": [
296 | "Success!\n"
297 | ]
298 | }
299 | ],
300 | "source": [
301 | "assert_eq!(p1(5772), 232961446);\n",
302 | "println!(\"Success!\");"
303 | ]
304 | },
305 | {
306 | "cell_type": "markdown",
307 | "metadata": {},
308 | "source": [
309 | "## The Third Constraint - Succinctness\n",
310 | "\n",
311 | "The last constraint's rational function is slightly more complicated:
\n",
312 | "\n",
313 | "\n",
314 | "$$p_2(x) = \\frac{f(g^2 \\cdot x) - (f(g \\cdot x))^2 - (f(x))^2}{\\prod\\limits_{i=0}^{1020} (x-g^i)}$$\n",
315 | "\n",
316 | "whose denominator can be rewritten, so that the entire expression is easier to compute:
\n",
317 | "\n",
318 | "$$\\frac{f(g^2 \\cdot x) - (f(g \\cdot x))^2 - (f(x))^2}{\\frac{x^{1024} - 1}{(x-g^{1021})(x-g^{1022})(x-g^{1023})}}$$
\n",
319 | "\n",
320 | "This follows from the equality\n",
321 | "\n",
322 | "$$\\prod\\limits_{i=0}^{1023} (x-g^i) = x^{1024} - 1$$\n",
323 | "\n",
324 | "Convince yourself of this equality using the function `prod` that takes a list and computes its product:"
325 | ]
326 | },
327 | {
328 | "cell_type": "code",
329 | "execution_count": 20,
330 | "metadata": {},
331 | "outputs": [
332 | {
333 | "name": "stderr",
334 | "output_type": "stream",
335 | "text": [
336 | "thread '' panicked at 'not yet implemented', src/lib.rs:134:28\n",
337 | "stack backtrace:\n",
338 | " 0: _rust_begin_unwind\n",
339 | " 1: core::panicking::panic_fmt\n",
340 | " 2: core::panicking::panic\n",
341 | " 3: as core::ops::function::FnOnce<()>>::call_once\n",
342 | " 4: _run_user_code_14\n",
343 | " 5: evcxr::runtime::Runtime::run_loop\n",
344 | " 6: evcxr::runtime::runtime_hook\n",
345 | " 7: evcxr_jupyter::main\n",
346 | "note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.\n"
347 | ]
348 | }
349 | ],
350 | "source": [
351 | "// Construct a list `lst` of the linear terms (x-g**i):\n",
352 | "let lst: Vec = todo!();\n",
353 | "// Compute the product of `lst` and see that it is indeed the succinct polynomial x**1024 - 1\n",
354 | "Polynomial::prod(&lst);"
355 | ]
356 | },
357 | {
358 | "cell_type": "markdown",
359 | "metadata": {},
360 | "source": [
361 | "Solution:"
362 | ]
363 | },
364 | {
365 | "cell_type": "code",
366 | "execution_count": 7,
367 | "metadata": {
368 | "tags": []
369 | },
370 | "outputs": [
371 | {
372 | "data": {
373 | "text/plain": [
374 | "Polynomial([FieldElement(3221225472), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(0), FieldElement(1)])"
375 | ]
376 | },
377 | "execution_count": 7,
378 | "metadata": {},
379 | "output_type": "execute_result"
380 | }
381 | ],
382 | "source": [
383 | "let lst: Vec = (0..1024).into_iter().map(|i| x() - g.pow(i)).collect();\n",
384 | "Polynomial::prod(&lst)"
385 | ]
386 | },
387 | {
388 | "cell_type": "markdown",
389 | "metadata": {},
390 | "source": [
391 | "For more information, see our blog post titled [Arithmetization II](https://medium.com/starkware/arithmetization-ii-403c3b3f4355).\n",
392 | "\n",
393 | "Let's pause for a moment, and look at a simple example on how polynomials are composed. After that we will generate the third constraint."
394 | ]
395 | },
396 | {
397 | "cell_type": "markdown",
398 | "metadata": {},
399 | "source": [
400 | "### Composing Polynomials (a detour)\n",
401 | "\n",
402 | "Create the two polynomials $q(x) = 2x^2 +1$, $r(x) = x - 3$:"
403 | ]
404 | },
405 | {
406 | "cell_type": "code",
407 | "execution_count": 22,
408 | "metadata": {},
409 | "outputs": [],
410 | "source": [
411 | "let q: Polynomial = x().pow(2)*2usize + 1;\n",
412 | "let r = x() - 3usize;"
413 | ]
414 | },
415 | {
416 | "cell_type": "markdown",
417 | "metadata": {},
418 | "source": [
419 | "Composing $q$ on $r$ yields a new polynomial:
\n",
420 | "$q(r(x)) = 2(x-3)^2 + 1 = 2x^2-12x+19$\n",
421 | "
\n",
422 | "Run the following cell to create a third polynomial `cmp` by composing `q` on `r` and convince yourself that `cmp` is indeed the composition of `q` and `r`:"
423 | ]
424 | },
425 | {
426 | "cell_type": "code",
427 | "execution_count": 23,
428 | "metadata": {},
429 | "outputs": [
430 | {
431 | "data": {
432 | "text/plain": [
433 | "Polynomial([FieldElement(19), FieldElement(3221225461), FieldElement(2)])"
434 | ]
435 | },
436 | "execution_count": 23,
437 | "metadata": {},
438 | "output_type": "execute_result"
439 | }
440 | ],
441 | "source": [
442 | "let cmp = q(r);\n",
443 | "cmp"
444 | ]
445 | },
446 | {
447 | "cell_type": "markdown",
448 | "metadata": {},
449 | "source": [
450 | "### Back to Polynomial Constraints\n",
451 | "Construct the third constraint `p2` in a similar manner to the construction of `p0` and `p1`, using polynomial composition. Along the way, verify that $g^{1020}$ is a root of the **numerator** while $g^{1021}$ is not."
452 | ]
453 | },
454 | {
455 | "cell_type": "code",
456 | "execution_count": null,
457 | "metadata": {},
458 | "outputs": [],
459 | "source": [
460 | "let p2: Polynomial = todo!();"
461 | ]
462 | },
463 | {
464 | "cell_type": "markdown",
465 | "metadata": {},
466 | "source": [
467 | "Solution:"
468 | ]
469 | },
470 | {
471 | "cell_type": "code",
472 | "execution_count": 145,
473 | "metadata": {
474 | "tags": []
475 | },
476 | "outputs": [
477 | {
478 | "name": "stdout",
479 | "output_type": "stream",
480 | "text": [
481 | "Numerator at g^1020 is FieldElement(0)\n",
482 | "Numerator at g^1021 is FieldElement(230576507)\n"
483 | ]
484 | }
485 | ],
486 | "source": [
487 | "let numer_1: Polynomial = f(x() * g.pow(2));\n",
488 | "let numer_2: Polynomial = f(x() * g).pow(2) * FieldElement::new((-1 + FieldElement::k_modulus() as i128) as usize);\n",
489 | "let numer_3: Polynomial = f.pow(2) * FieldElement::new((-1 + FieldElement::k_modulus() as i128) as usize);\n",
490 | "let numer2: Polynomial = numer_1 + numer_2 + numer_3;\n",
491 | "println!(\"Numerator at g^1020 is {:?}\", numer2.clone()(g.pow(1020)));\n",
492 | "println!(\"Numerator at g^1021 is {:?}\", numer2(g.pow(1021usize)));\n",
493 | "let denom2 = (x().pow(1024usize) - 1) / ((x() - g.pow(1021)) * (x() - g.pow(1022)) * (x() - g.pow(1023)));\n",
494 | "\n",
495 | "let p2: Polynomial = numer2 / denom2;"
496 | ]
497 | },
498 | {
499 | "cell_type": "markdown",
500 | "metadata": {},
501 | "source": [
502 | "Run test:"
503 | ]
504 | },
505 | {
506 | "cell_type": "code",
507 | "execution_count": 17,
508 | "metadata": {
509 | "scrolled": true
510 | },
511 | "outputs": [
512 | {
513 | "name": "stdout",
514 | "output_type": "stream",
515 | "text": [
516 | "Success!\n"
517 | ]
518 | }
519 | ],
520 | "source": [
521 | "let p2_degree = p2.degree();\n",
522 | "assert_eq!(p2.degree(), 1023, \"The degree of the third constraint is {p2_degree} when it should be 1023.\");\n",
523 | "assert_eq!(p2(31415), 2090051528);\n",
524 | "println!(\"Success!\");"
525 | ]
526 | },
527 | {
528 | "cell_type": "markdown",
529 | "metadata": {},
530 | "source": [
531 | "Run the following cell to observe the degrees of the constraint polynomials `p0`, `p1` and `p2`, all less than $1024$. This will be important in the next part."
532 | ]
533 | },
534 | {
535 | "cell_type": "code",
536 | "execution_count": 50,
537 | "metadata": {},
538 | "outputs": [
539 | {
540 | "name": "stdout",
541 | "output_type": "stream",
542 | "text": [
543 | "deg p0 = 1021\n",
544 | "deg p1 = 1021\n",
545 | "deg p2 = 1023\n"
546 | ]
547 | }
548 | ],
549 | "source": [
550 | "println!(\"deg p0 = {}\", p0.degree());\n",
551 | "println!(\"deg p1 = {}\", p1.degree());\n",
552 | "println!(\"deg p2 = {}\", p2.degree());"
553 | ]
554 | },
555 | {
556 | "cell_type": "markdown",
557 | "metadata": {},
558 | "source": [
559 | "### Step 4 - Composition Polynomial\n",
560 | "Recall that we're translating a problem of checking the validity of three polynomial constraints to checking that each of the rational functions $p_0, p_1, p_2$ are polynomials.
\n",
561 | "\n",
562 | "Our protocol uses an algorithm called [FRI](https://eccc.weizmann.ac.il/report/2017/134/) to do so, which will be discussed in the next part.
\n",
563 | "In order for the proof to be succinct (short), we prefer to work with just one rational function instead of three. For that, we take a random linear combination of $p_0, p_1, p_2$ called the **compostion polynomial** (CP for short):\n",
564 | "\n",
565 | "$$CP(x) = \\alpha_0 \\cdot p_0(x) + \\alpha_1 \\cdot p_1(x) + \\alpha_2 \\cdot p_2(x)$$
\n",
566 | "\n",
567 | "where $\\alpha_0, \\alpha_1, \\alpha_2 $ are random field elements obtained from the verifier, or in our case - from the channel.\n",
568 | "\n",
569 | "Proving that (the rational function) $CP$ is a polynomial guarantess, with high probability, that each of $p_0$, $p_1$, $p_2$ are themselves polynomials.\n",
570 | "\n",
571 | "In the next part, you will generate a proof for an equivalent fact. But first, let's create `CP` using `Channel.receive_random_field_element` to obtain $\\alpha_i$:
\n",
572 | " "
573 | ]
574 | },
575 | {
576 | "cell_type": "code",
577 | "execution_count": null,
578 | "metadata": {},
579 | "outputs": [],
580 | "source": [
581 | "// Note that alpha0, alpha1, alpha2 have to be drawn from the channel in this order.\n",
582 | "fn get_CP(p1: Polynomial, p2: Polynomial, p3: Polynomial, channel: Channel) -> Polynomial {\n",
583 | " todo!();\n",
584 | "}"
585 | ]
586 | },
587 | {
588 | "cell_type": "markdown",
589 | "metadata": {},
590 | "source": [
591 | "Solution:"
592 | ]
593 | },
594 | {
595 | "cell_type": "code",
596 | "execution_count": 146,
597 | "metadata": {
598 | "tags": []
599 | },
600 | "outputs": [],
601 | "source": [
602 | "fn get_CP(p0: Polynomial, p1: Polynomial, p2: Polynomial, channel: &mut Channel) -> Polynomial {\n",
603 | " let alpha0 = channel.receive_random_field_element();\n",
604 | " let alpha1 = channel.receive_random_field_element();\n",
605 | " let alpha2 = channel.receive_random_field_element();\n",
606 | " (p0 * alpha0) + (p1 * alpha1) + (p2 * alpha2)\n",
607 | "}"
608 | ]
609 | },
610 | {
611 | "cell_type": "markdown",
612 | "metadata": {},
613 | "source": [
614 | "Run test:"
615 | ]
616 | },
617 | {
618 | "cell_type": "code",
619 | "execution_count": 138,
620 | "metadata": {},
621 | "outputs": [
622 | {
623 | "name": "stdout",
624 | "output_type": "stream",
625 | "text": [
626 | "Success!\n"
627 | ]
628 | }
629 | ],
630 | "source": [
631 | "let mut test_channel: Channel = Channel::new();\n",
632 | "let cp_test = get_CP(p0, p1, p2, &mut test_channel);\n",
633 | "let cp_test_degree = cp_test.degree();\n",
634 | "assert_eq!(cp_test.degree(), 1023, \"The degree of cp is {cp_test_degree} when it should be 1023.\");\n",
635 | "let expected = cp_test(2439804);\n",
636 | "assert_eq!(cp_test(2439804), 838767343, \"cp(2439804) = {expected:?}, when it should be 838767343\");\n",
637 | "println!(\"Success!\");"
638 | ]
639 | },
640 | {
641 | "cell_type": "markdown",
642 | "metadata": {},
643 | "source": [
644 | "### Commit on the Composition Polynomial\n",
645 | "Lastly, we evaluate $cp$ over the evaluation domain (`eval_domain`), build a Merkle tree on top of that and send its root over the channel. This is similar to commiting on the LDE trace, as we did at the end of part 1."
646 | ]
647 | },
648 | {
649 | "cell_type": "code",
650 | "execution_count": null,
651 | "metadata": {},
652 | "outputs": [],
653 | "source": [
654 | "// Fix this. CP_eval is the evaluation of CP on all the points in domain. For a hint - look at \"Evaluate on a Coset\" on part 1.\n",
655 | "fn cp_eval(p0: Polynomial, p1: Polynomial, p2: Polynomial, domain: Vec, channel: &mut Channel) {\n",
656 | " let cp = get_CP(p0, p1, p2, channel);\n",
657 | " todo!();\n",
658 | "}"
659 | ]
660 | },
661 | {
662 | "cell_type": "markdown",
663 | "metadata": {},
664 | "source": [
665 | "Solution:"
666 | ]
667 | },
668 | {
669 | "cell_type": "code",
670 | "execution_count": 147,
671 | "metadata": {
672 | "tags": []
673 | },
674 | "outputs": [],
675 | "source": [
676 | "fn cp_eval(p0: Polynomial, p1: Polynomial, p2: Polynomial, domain: Vec, channel: &mut Channel) -> Vec {\n",
677 | " let cp = get_CP(p0, p1, p2, channel);\n",
678 | " domain.into_iter().map(|d| cp(d)).collect()\n",
679 | "}"
680 | ]
681 | },
682 | {
683 | "cell_type": "markdown",
684 | "metadata": {},
685 | "source": [
686 | "Construct a Merkle Tree over the evaluation and send its root over the channel."
687 | ]
688 | },
689 | {
690 | "cell_type": "code",
691 | "execution_count": null,
692 | "metadata": {},
693 | "outputs": [],
694 | "source": [
695 | "let channel = Channel::new();\n",
696 | "let cp_merkle = MerkleTree::new(todo!()); // Fix this line\n",
697 | "channel.send(cp_merkle.root);"
698 | ]
699 | },
700 | {
701 | "cell_type": "markdown",
702 | "metadata": {},
703 | "source": [
704 | "Solution:"
705 | ]
706 | },
707 | {
708 | "cell_type": "code",
709 | "execution_count": 148,
710 | "metadata": {
711 | "tags": []
712 | },
713 | "outputs": [],
714 | "source": [
715 | "use stark101_rs::merkle_tree::MerkleTree;\n",
716 | "let mut channel = Channel::new();\n",
717 | "let cp_merkle: MerkleTree = MerkleTree::new(cp_eval(p0, p1, p2, eval_domain, &mut channel));\n",
718 | "channel.send(cp_merkle.root());"
719 | ]
720 | },
721 | {
722 | "cell_type": "markdown",
723 | "metadata": {},
724 | "source": [
725 | "Test your code:"
726 | ]
727 | },
728 | {
729 | "cell_type": "code",
730 | "execution_count": 150,
731 | "metadata": {},
732 | "outputs": [
733 | {
734 | "name": "stdout",
735 | "output_type": "stream",
736 | "text": [
737 | "Success!\n"
738 | ]
739 | }
740 | ],
741 | "source": [
742 | "assert_eq!(cp_merkle.root(), \"26db4de93f69af9591eac0bf224a26f5ffd99d07a325b82ee34381069a205a53\", \"Merkle tree root is wrong.\");\n",
743 | "println!(\"Success!\");"
744 | ]
745 | }
746 | ],
747 | "metadata": {
748 | "kernelspec": {
749 | "display_name": "Rust",
750 | "language": "rust",
751 | "name": "rust"
752 | },
753 | "language_info": {
754 | "codemirror_mode": "rust",
755 | "file_extension": ".rs",
756 | "mimetype": "text/rust",
757 | "name": "Rust",
758 | "pygment_lexer": "rust",
759 | "version": ""
760 | }
761 | },
762 | "nbformat": 4,
763 | "nbformat_minor": 4
764 | }
765 |
--------------------------------------------------------------------------------
/part3.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "*Copyright 2019 StarkWare Industries Ltd.
Licensed under the Apache License, Version 2.0 (the \"License\"). You may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.starkware.co/open-source-license/
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Part 3: FRI Commitments"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {
20 | "tags": []
21 | },
22 | "source": [
23 | "- [Video Lecture (youtube)](https://www.youtube.com/watch?v=gd1NbKUOJwA)\n",
24 | "- [Slides (PDF)](https://starkware.co/wp-content/uploads/2021/12/STARK101-Part3.pdf)\n",
25 | "\n",
26 | "### Load Previous Session\n",
27 | "Run the next cell to load the relevant variables. As usual - it will take a while to run."
28 | ]
29 | },
30 | {
31 | "cell_type": "code",
32 | "execution_count": 63,
33 | "metadata": {
34 | "vscode": {
35 | "languageId": "rust"
36 | }
37 | },
38 |
39 | "outputs": [
40 | {
41 | "name": "stdout",
42 | "output_type": "stream",
43 | "text": [
44 | "Success!\n"
45 | ]
46 | }
47 | ],
48 | "source": [
49 | ":dep stark101-rs = { path = \"stark101\" }\n",
50 | ":dep sha256 = \"1.1.2\"\n",
51 | "use stark101_rs::{field::FieldElement, channel::Channel, polynomial::{Polynomial, x}, merkle_tree::MerkleTree};\n",
52 | "use stark101_rs::parts::part2;\n",
53 | "\n",
54 | "let (cp, cp_eval, cp_merkle, channel, eval_domain) = part2();\n",
55 | "println!(\"Success!\");"
56 | ]
57 | },
58 | {
59 | "cell_type": "markdown",
60 | "metadata": {},
61 | "source": [
62 | "## FRI Folding\n",
63 | "\n",
64 | "Our goal in this part is to construct the FRI layers and commit on them. \n",
65 | "
To obtain each layer we need:\n",
66 | "1. To generate a domain for the layer (from the previous layer's domain).\n",
67 | "2. To generate a polynomial for the layer (from the previous layer's polynomial and domain).\n",
68 | "3. To evaluate said polynomial on said domain - **this is the next FRI layer**."
69 | ]
70 | },
71 | {
72 | "cell_type": "markdown",
73 | "metadata": {},
74 | "source": [
75 | "### Domain Generation\n",
76 | "\n",
77 | "The first FRI domain is simply the `eval_domain` that you already generated in Part 1, namely a coset of a group of order 8192. Each subsequent FRI domain is obtained by taking the first half of the previous FRI domain (dropping the second half), and squaring each of its elements.
\n",
78 | "\n",
79 | "Formally - we got `eval_domain` by taking:
\n",
80 | "$$w, w\\cdot h, w\\cdot h^2, ..., w\\cdot h^{8191}$$\n",
81 | "\n",
82 | "The next layer will therefore be:
\n",
83 | "$$w^2, (w\\cdot h)^2, (w\\cdot h^2)^2, ..., (w\\cdot h^{4095})^2$$"
84 | ]
85 | },
86 | {
87 | "cell_type": "markdown",
88 | "metadata": {},
89 | "source": [
90 | "Note that taking the squares of the second half of each elements in `eval_domain` yields exactly\n",
91 | "the same result as taking the squares of the first half. This is true for the next layers as well.\n",
92 | "For example:"
93 | ]
94 | },
95 | {
96 | "cell_type": "code",
97 | "execution_count": 37,
98 | "metadata": {
99 | "vscode": {
100 | "languageId": "rust"
101 | }
102 | },
103 | "outputs": [
104 | {
105 | "name": "stdout",
106 | "output_type": "stream",
107 | "text": [
108 | "FieldElement(2848063603)\n",
109 | "FieldElement(2848063603)\n"
110 | ]
111 | }
112 | ],
113 | "source": [
114 | "println!(\"{:?}\", eval_domain[100].pow(2));\n",
115 | "let half_domain_size: usize = eval_domain.len() / 2;\n",
116 | "println!(\"{:?}\", eval_domain[half_domain_size + 100].pow(2));"
117 | ]
118 | },
119 | {
120 | "cell_type": "markdown",
121 | "metadata": {},
122 | "source": [
123 | "Similarly, the domain of the third layer will be:
\n",
124 | "$$w^4, (w\\cdot h)^4, (w\\cdot h^2)^4, ..., (w\\cdot h^{2047})^4$$\n",
125 | "\n",
126 | "And so on."
127 | ]
128 | },
129 | {
130 | "cell_type": "markdown",
131 | "metadata": {},
132 | "source": [
133 | "Write a function `next_fri_domain` that takes the previous domain as an argument, and outputs the next one."
134 | ]
135 | },
136 | {
137 | "cell_type": "code",
138 | "execution_count": 3,
139 |
140 | "metadata": {
141 | "vscode": {
142 | "languageId": "rust"
143 | }
144 | },
145 | "outputs": [],
146 | "source": [
147 | "fn next_fri_domain(fri_domain: Vec) -> Vec {\n",
148 | " // Fix this.\n",
149 | "}"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "Solution:"
157 | ]
158 | },
159 | {
160 | "cell_type": "code",
161 | "execution_count": 54,
162 | "metadata": {
163 | "tags": [],
164 | "vscode": {
165 | "languageId": "rust"
166 | }
167 | },
168 | "outputs": [],
169 | "source": [
170 | "fn next_fri_domain(fri_domain: Vec) -> Vec {\n",
171 | " let fri_domain_len = fri_domain.len();\n",
172 | " fri_domain.into_iter().take(fri_domain_len / 2).map(|x| x.pow(2)).collect()\n",
173 | "}"
174 | ]
175 | },
176 | {
177 | "cell_type": "markdown",
178 | "metadata": {},
179 | "source": [
180 | "Run test: "
181 | ]
182 | },
183 | {
184 | "cell_type": "code",
185 | "execution_count": 5,
186 | "metadata": {
187 | "vscode": {
188 | "languageId": "rust"
189 | }
190 | },
191 | "outputs": [
192 | {
193 | "ename": "Error",
194 | "evalue": "expected `;`, found `println`",
195 | "output_type": "error",
196 | "traceback": [
197 | "\u001b[31mError:\u001b[0m expected `;`, found `println`",
198 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_5:1:1\u001b[38;5;246m]\u001b[0m",
199 | " \u001b[38;5;246m│\u001b[0m",
200 | " \u001b[38;5;246m3 │\u001b[0m \u001b[38;5;249ma\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mq\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m9\u001b[0m\u001b[38;5;249m0\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m9\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m8\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m8\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m9\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249m0\u001b[0m\u001b[38;5;249m8\u001b[0m\u001b[38;5;249m7\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m8\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m7\u001b[0m\u001b[38;5;249m7\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m4\u001b[0m\u001b[38;5;249mb\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m3\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m7\u001b[0m\u001b[38;5;249m9\u001b[0m\u001b[38;5;249m7\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m5\u001b[0m\u001b[38;5;249m6\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m'\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mj\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mg\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m)\u001b[0m",
201 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m│\u001b[0m ",
202 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m error: expected `;`, found `println`",
203 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m│\u001b[0m ",
204 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m help: add `;` here: `;`",
205 | " \u001b[38;5;246m4 │\u001b[0m \u001b[38;5;54mp\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mt\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249mS\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
206 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
207 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m unexpected token",
208 | "\u001b[38;5;246m───╯\u001b[0m"
209 | ]
210 | }
211 | ],
212 | "source": [
213 | "// Test against a precomputed hash.\n",
214 | "let next_domain = next_fri_domain(eval_domain);\n",
215 | "assert_eq!(\"5446c90d6ed23ea961513d4ae38fc6585f6614a3d392cb087e837754bfd32797\", sha256(','.join([str(i) for i in next_domain]).encode()).hexdigest());\n",
216 | "println!(\"Success!\");"
217 | ]
218 | },
219 | {
220 | "cell_type": "markdown",
221 | "metadata": {},
222 | "source": [
223 | "### FRI Folding Operator\n",
224 | "The first FRI polynomial is simply the composition polynomial, i.e., `cp`.
\n",
225 | "Each subsequent FRI polynomial is obtained by:\n",
226 | "1. Getting a random field element $\\beta$ (by calling `Channel.receive_random_field_element`).\n",
227 | "2. Multiplying the odd coefficients of the previous polynomial by $\\beta$.\n",
228 | "3. Summing together consecutive pairs (even-odd) of coefficients.\n",
229 | "\n",
230 | "Formally, let's say that the k-th polynomial is of degree $< m$ (for some $m$ which is a power of 2):\n",
231 | "\n",
232 | "$$p_{k}(x) := \\sum _{i=0} ^{m-1} c_i x^i$$\n",
233 | "\n",
234 | "\n",
235 | "Then the (k+1)-th polynomial, whose degree is $< \\frac m 2 $ will be:\n",
236 | "\n",
237 | "$$p_{k+1}(x) := \\sum _{i=0} ^{ m / 2 - 1 } (c_{2i} + \\beta \\cdot c_{2i + 1}) x^i$$"
238 | ]
239 | },
240 | {
241 | "cell_type": "markdown",
242 | "metadata": {},
243 | "source": [
244 | "Write a function `next_fri_polynomial` that takes as arguments a polynomial and a field element (the one we referred to as $\\beta$), and returns the \"folded\" next polynomial.\n",
245 | "\n",
246 | "Note that:\n",
247 | "1. `Polynomial.poly` contains a list of a polynomial's coefficients, the free term first, and the highest degree last, so `p.poly[i] == u` if the coefficient of $x^i$ is $u$.*\n",
248 | "2. `Polynomial`'s default constructor takes the list of coefficients as argument. So a polynomial can be instantiated from a list of coefficients `l` by calling `Polynomial(l)`.\n"
249 | ]
250 | },
251 | {
252 | "cell_type": "code",
253 | "execution_count": 39,
254 | "metadata": {
255 | "vscode": {
256 | "languageId": "rust"
257 | }
258 | },
259 | "outputs": [
260 | {
261 | "ename": "Error",
262 | "evalue": "expected one of `.`, `?`, `]`, or an operator, found `::`",
263 | "output_type": "error",
264 | "traceback": [
265 | "\u001b[31mError:\u001b[0m expected one of `.`, `?`, `]`, or an operator, found `::`",
266 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_39:1:1\u001b[38;5;246m]\u001b[0m",
267 | " \u001b[38;5;246m│\u001b[0m",
268 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249m[\u001b[0m\u001b[38;5;249m1\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;54m:\u001b[0m\u001b[38;5;249m2\u001b[0m\u001b[38;5;249m]\u001b[0m\u001b[38;5;249m;\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m/\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mx\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m",
269 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
270 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected one of `.`, `?`, `]`, or an operator",
271 | "\u001b[38;5;246m───╯\u001b[0m"
272 | ]
273 | }
274 | ],
275 | "source": [
276 | "fn next_fri_polynomial(poly: Polynomial, beta: FieldElement) -> Polynomial {\n",
277 | " let odd_coefficients = poly.poly[1::2]; // fix this line.\n",
278 | " let even_coefficients = poly.poly[::2]; // No need to fix this line either.\n",
279 | " let multiplied_by_beta: Vec = odd_coefficients.into_iter().map(|c| c * beta).collect();\n",
280 | " let odd = Polynomial::new(&multiplied_by_beta);\n",
281 | " let even = Polynomial(even_coefficients);\n",
282 | " odd + even\n",
283 | "}"
284 | ]
285 | },
286 | {
287 | "cell_type": "markdown",
288 | "metadata": {},
289 | "source": [
290 | "Solution:"
291 | ]
292 | },
293 | {
294 | "cell_type": "code",
295 |
296 | "execution_count": 55,
297 | "metadata": {
298 | "tags": [],
299 | "vscode": {
300 | "languageId": "rust"
301 | }
302 | },
303 | "outputs": [],
304 | "source": [
305 | "fn next_fri_polynomial(poly: Polynomial, beta: FieldElement) -> Polynomial {\n",
306 | " let odd_coefficients: Vec = poly.0.clone().into_iter().skip(1).step_by(2).collect();\n",
307 | " let even_coefficients: Vec = poly.0.into_iter().step_by(2).collect();\n",
308 | " let odd = Polynomial::new(&odd_coefficients) * beta;\n",
309 | " let even = Polynomial::new(&even_coefficients);\n",
310 | " odd + even\n",
311 | "}"
312 | ]
313 | },
314 | {
315 | "cell_type": "markdown",
316 | "metadata": {},
317 | "source": [
318 | "Run test:"
319 | ]
320 | },
321 | {
322 | "cell_type": "code",
323 | "execution_count": 6,
324 | "metadata": {
325 | "vscode": {
326 | "languageId": "rust"
327 | }
328 | },
329 | "outputs": [
330 | {
331 | "name": "stdout",
332 | "output_type": "stream",
333 | "text": [
334 | "Success!\n"
335 | ]
336 | }
337 | ],
338 | "source": [
339 | "let next_p = next_fri_polynomial(cp, FieldElement::new(987654321));\n",
340 | "assert_eq!(\"6bff4c35e1aa9693f9ceb1599b6a484d7636612be65990e726e52a32452c2154\", sha256(','.join([str(i) for i in next_p.poly]).encode()).hexdigest());\n",
341 | "println!(\"Success!\");"
342 | ]
343 | },
344 | {
345 | "cell_type": "markdown",
346 | "metadata": {},
347 | "source": [
348 | "### Putting it Together to Get the Next FRI Layer\n",
349 | "\n",
350 | "Write a function `next_fri_layer` that takes a polynomial, a domain, and a field element (again - $\\beta$), and returns the next polynomial, the next domain, and the evaluation of this next polynomial on this next domain."
351 | ]
352 | },
353 | {
354 | "cell_type": "code",
355 | "execution_count": 7,
356 | "metadata": {
357 | "vscode": {
358 | "languageId": "rust"
359 | }
360 | },
361 | "outputs": [],
362 | "source": [
363 | "fn next_fri_layer(poly: Polynomial, domain: Vec, beta: FieldElement) -> (Polynomial, Vec, Vec) {\n",
364 | " todo!()\n",
365 | "}"
366 | ]
367 | },
368 | {
369 | "cell_type": "markdown",
370 | "metadata": {},
371 | "source": [
372 | "Solution:"
373 | ]
374 | },
375 | {
376 | "cell_type": "code",
377 |
378 | "execution_count": 56,
379 | "metadata": {
380 | "tags": [],
381 | "vscode": {
382 | "languageId": "rust"
383 | }
384 | },
385 | "outputs": [],
386 | "source": [
387 | "fn next_fri_layer(poly: Polynomial, domain: Vec, beta: FieldElement) -> (Polynomial, Vec, Vec) {\n",
388 | " let next_poly = next_fri_polynomial(poly, beta);\n",
389 | " let next_domain = next_fri_domain(domain);\n",
390 | " let next_layer: Vec = next_domain.clone().into_iter().map(|x| next_poly(x)).collect();\n",
391 | " (next_poly, next_domain, next_layer)\n",
392 | "}"
393 | ]
394 | },
395 | {
396 | "cell_type": "markdown",
397 | "metadata": {},
398 | "source": [
399 | "Run test:"
400 | ]
401 | },
402 | {
403 | "cell_type": "code",
404 | "execution_count": 42,
405 | "metadata": {
406 | "vscode": {
407 | "languageId": "rust"
408 | }
409 | },
410 | "outputs": [
411 | {
412 | "name": "stdout",
413 | "output_type": "stream",
414 | "text": [
415 | "Success!\n"
416 | ]
417 | }
418 | ],
419 | "source": [
420 | "let test_poly = Polynomial::new(&[FieldElement::new(2), FieldElement::new(3), FieldElement::new(0), FieldElement::new(1)]);\n",
421 | "let test_domain = vec![FieldElement::new(3), FieldElement::new(5)];\n",
422 | "let beta = FieldElement::new(7);\n",
423 | "let (next_p, next_d, next_l) = next_fri_layer(test_poly, test_domain, beta);\n",
424 | "assert_eq!(next_p, Polynomial::new(&[FieldElement::new(23), FieldElement::new(7)]));\n",
425 | "assert_eq!(next_d, vec![FieldElement::new(9)]);\n",
426 | "assert_eq!(next_l, vec![FieldElement::new(86)]);\n",
427 | "println!(\"Success!\");"
428 | ]
429 | },
430 | {
431 | "cell_type": "markdown",
432 | "metadata": {},
433 | "source": [
434 | "## Generating FRI Commitments\n",
435 | "\n",
436 | "We have now developed the tools to write the `FriCommit` method, that contains the main FRI commitment loop.
\n",
437 | "\n",
438 | "It takes the following 5 arguments:\n",
439 | "1. The composition polynomial, that is also the first FRI polynomial, that is - `cp`.\n",
440 | "2. The coset of order 8192 that is also the first FRI domain, that is - `eval_domain`.\n",
441 | "3. The evaluation of the former over the latter, which is also the first FRI layer , that is - `cp_eval`.\n",
442 | "4. The first Merkle tree (we will have one for each FRI layer) constructed from these evaluations, that is - `cp_merkle`.\n",
443 | "5. A channel object, that is `channel`.\n",
444 | "\n",
445 | "The method accordingly returns 4 lists:\n",
446 | "1. The FRI polynomials.\n",
447 | "2. The FRI domains.\n",
448 | "3. The FRI layers.\n",
449 | "4. The FRI Merkle trees.\n",
450 | "\n",
451 | "The method contains a loop, in each iteration of which we extend these four lists, using the last element in each.\n",
452 | "The iteration should stop once the last FRI polynomial is of degree 0, that is - when the last FRI polynomial is just a constant. It should then send over the channel this constant (i.e. - the polynomial's free term).\n",
453 | "The `Channel` class only supports sending strings, so make sure you convert anything you wish to send over the channel to a string before sending."
454 | ]
455 | },
456 | {
457 | "cell_type": "code",
458 | "execution_count": 9,
459 | "metadata": {
460 | "vscode": {
461 | "languageId": "rust"
462 | }
463 | },
464 | "outputs": [],
465 | "source": [
466 | "// Fix this according to the instructions (lines with no specific comments are okay).\n",
467 | "fn fri_commit(cp, domain, cp_eval, cp_merkle, channel) -> (Vec, Vec>, Vec>, Vec) {\n",
468 | " let fri_polys: Vec = vec![cp];\n",
469 | " let fri_domains: Vec> = vec![domain];\n",
470 | " let fri_layers: Vec> = vec![cp_eval];\n",
471 | " let fri_merkles: Vec = vec![cp_merkle];\n",
472 | " while cp.degree() > 1 { // Replace this with the correct halting condition.\n",
473 | " let beta = channel.receive_random_field_element(); // Change to obtain a random element from the channel.\n",
474 | " let (next_poly, next_domain, next_layer) = next_fri_layer(cp, domain, beta); // Fix to obtain the next FRI polynomial, domain, and layer.\n",
475 | " fri_polys.push(next_poly);\n",
476 | " fri_domains.push(next_domain);\n",
477 | " fri_layers.push(next_layer);\n",
478 | " fri_merkles.push(MerkleTree::new(next_layer)); // Fix to construct the correct Merkle tree.\n",
479 | " channel.send(fri_merkles.last().unwrap().root()); // Fix to send the correct commitment.\n",
480 | " }\n",
481 | " channel.send(fri_polys.last().unwrap()) // Fix to send the last layer's free term.\n",
482 | " (fri_polys, fri_domains, fri_layers, fri_merkles)\n",
483 | "}"
484 | ]
485 | },
486 | {
487 | "cell_type": "markdown",
488 | "metadata": {},
489 | "source": [
490 | "Solution:"
491 | ]
492 | },
493 | {
494 | "cell_type": "code",
495 | "execution_count": 57,
496 | "metadata": {
497 | "tags": [],
498 | "vscode": {
499 | "languageId": "rust"
500 | }
501 | },
502 | "outputs": [],
503 | "source": [
504 | "fn fri_commit(cp: Polynomial, domain: Vec, cp_eval: Vec, cp_merkle: MerkleTree, channel: &mut Channel) -> (Vec, Vec>, Vec>, Vec) { \n",
505 | " let mut fri_polys: Vec = vec![cp];\n",
506 | " let mut fri_domains: Vec> = vec![domain];\n",
507 | " let mut fri_layers: Vec> = vec![cp_eval];\n",
508 | " let mut fri_merkles: Vec = vec![cp_merkle];\n",
509 | " while fri_polys.last().unwrap().degree() > 0 {\n",
510 | " let beta = channel.receive_random_field_element();\n",
511 | " let last_poly = fri_polys.last().unwrap().clone();\n",
512 | " let last_domain = fri_domains.last().unwrap().clone();\n",
513 | " let (next_poly, next_domain, next_layer) = next_fri_layer(last_poly, last_domain, beta);\n",
514 | " fri_polys.push(next_poly.clone());\n",
515 | " fri_domains.push(next_domain.clone());\n",
516 | " fri_layers.push(next_layer.clone());\n",
517 | " fri_merkles.push(MerkleTree::new(next_layer));\n",
518 | " channel.send(fri_merkles.last().unwrap().root())\n",
519 | " }\n",
520 | " channel.send(fri_polys.last().unwrap().0[0].0.to_string());\n",
521 | "\n",
522 | " (fri_polys, fri_domains, fri_layers, fri_merkles)\n",
523 | "}"
524 | ]
525 | },
526 | {
527 | "cell_type": "markdown",
528 | "metadata": {},
529 | "source": [
530 | "Run test:"
531 | ]
532 | },
533 | {
534 | "cell_type": "code",
535 | "execution_count": 60,
536 | "metadata": {
537 | "vscode": {
538 | "languageId": "rust"
539 | }
540 | },
541 | "outputs": [
542 | {
543 | "ename": "Error",
544 | "evalue": "cannot find value `cp` in this scope",
545 | "output_type": "error",
546 | "traceback": [
547 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp` in this scope",
548 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_60:1:1\u001b[38;5;246m]\u001b[0m",
549 | " \u001b[38;5;246m│\u001b[0m",
550 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
551 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
552 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
553 | "\u001b[38;5;246m───╯\u001b[0m"
554 | ]
555 | },
556 | {
557 | "ename": "Error",
558 | "evalue": "cannot find value `eval_domain` in this scope",
559 | "output_type": "error",
560 | "traceback": [
561 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `eval_domain` in this scope",
562 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_60:1:1\u001b[38;5;246m]\u001b[0m",
563 | " \u001b[38;5;246m│\u001b[0m",
564 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
565 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
566 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
567 | "\u001b[38;5;246m───╯\u001b[0m"
568 | ]
569 | },
570 | {
571 | "ename": "Error",
572 | "evalue": "cannot find value `cp_eval` in this scope",
573 | "output_type": "error",
574 | "traceback": [
575 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp_eval` in this scope",
576 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_60:1:1\u001b[38;5;246m]\u001b[0m",
577 | " \u001b[38;5;246m│\u001b[0m",
578 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
579 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
580 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
581 | "\u001b[38;5;246m───╯\u001b[0m"
582 | ]
583 | },
584 | {
585 | "ename": "Error",
586 | "evalue": "cannot find value `cp_merkle` in this scope",
587 | "output_type": "error",
588 | "traceback": [
589 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp_merkle` in this scope",
590 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_60:1:1\u001b[38;5;246m]\u001b[0m",
591 | " \u001b[38;5;246m│\u001b[0m",
592 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mk\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m.\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m&\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mu\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
593 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
594 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
595 | "\u001b[38;5;246m───╯\u001b[0m"
596 | ]
597 | }
598 | ],
599 | "source": [
600 | "let mut test_channel = Channel::new();\n",
601 | "let (fri_polys, fri_domains, fri_layers, fri_merkles) = fri_commit(cp.clone(), eval_domain.clone(), cp_eval.clone(), cp_merkle.clone(), &mut test_channel);\n",
602 | "let fri_layers_len = fri_layers.len();\n",
603 | "assert_eq!(fri_layers_len, 11, \"Expected number of FRI layers is 11, whereas it is actually {fri_layers_len}\");\n",
604 | "assert_eq!(fri_layers.last().unwrap().len(), 8, \"Expected last layer to contain exactly 8 elements\");\n",
605 | "assert_eq!(fri_polys.last().unwrap().degree(), 0, \"Expected last polynomial to be constant (degree 0).\");\n",
606 | "assert_eq!(fri_merkles.last().unwrap().root(), \"6e09c7e19275df2155bd575833aa441f3058446726938420c0acabb1c332c40f\", \"Last layer Merkle root is wrong.\");\n",
607 | "\n",
608 | "println!(\"Success!\");"
609 | ]
610 | },
611 | {
612 | "cell_type": "markdown",
613 | "metadata": {},
614 | "source": [
615 | "Run the following cell to execute the function with your channel object and print the proof so far:"
616 | ]
617 | },
618 | {
619 | "cell_type": "code",
620 | "execution_count": 59,
621 | "metadata": {
622 | "vscode": {
623 | "languageId": "rust"
624 | }
625 | },
626 | "outputs": [
627 | {
628 | "ename": "Error",
629 | "evalue": "cannot find value `cp` in this scope",
630 | "output_type": "error",
631 | "traceback": [
632 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp` in this scope",
633 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
634 | " \u001b[38;5;246m│\u001b[0m",
635 | " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
636 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m ",
637 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
638 | "\u001b[38;5;246m───╯\u001b[0m"
639 | ]
640 | },
641 | {
642 | "ename": "Error",
643 | "evalue": "cannot find value `eval_domain` in this scope",
644 | "output_type": "error",
645 | "traceback": [
646 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `eval_domain` in this scope",
647 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
648 | " \u001b[38;5;246m│\u001b[0m",
649 | " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54md\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mi\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
650 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
651 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
652 | "\u001b[38;5;246m───╯\u001b[0m"
653 | ]
654 | },
655 | {
656 | "ename": "Error",
657 | "evalue": "cannot find value `cp_eval` in this scope",
658 | "output_type": "error",
659 | "traceback": [
660 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp_eval` in this scope",
661 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
662 | " \u001b[38;5;246m│\u001b[0m",
663 | " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mv\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
664 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
665 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
666 | "\u001b[38;5;246m───╯\u001b[0m"
667 | ]
668 | },
669 | {
670 | "ename": "Error",
671 | "evalue": "cannot find value `cp_merkle` in this scope",
672 | "output_type": "error",
673 | "traceback": [
674 | "\u001b[31m[E0425] Error:\u001b[0m cannot find value `cp_merkle` in this scope",
675 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
676 | " \u001b[38;5;246m│\u001b[0m",
677 | " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54m_\u001b[0m\u001b[38;5;54mm\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mk\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mh\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
678 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
679 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m not found in this scope",
680 | "\u001b[38;5;246m───╯\u001b[0m"
681 | ]
682 | },
683 | {
684 | "ename": "Error",
685 | "evalue": "mismatched types",
686 | "output_type": "error",
687 | "traceback": [
688 | "\u001b[31m[E0308] Error:\u001b[0m mismatched types",
689 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
690 | " \u001b[38;5;246m│\u001b[0m",
691 | " \u001b[38;5;246m1 │\u001b[0m \u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249my\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mf\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249ms\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249m=\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;100mf\u001b[0m\u001b[38;5;100mr\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100m_\u001b[0m\u001b[38;5;100mc\u001b[0m\u001b[38;5;100mo\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mm\u001b[0m\u001b[38;5;100mi\u001b[0m\u001b[38;5;100mt\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249md\u001b[0m\u001b[38;5;249mo\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mv\u001b[0m\u001b[38;5;249ma\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;249mc\u001b[0m\u001b[38;5;249mp\u001b[0m\u001b[38;5;249m_\u001b[0m\u001b[38;5;249mm\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mk\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249me\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
692 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m┬\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
693 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;100m╰\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m\u001b[38;5;100m─\u001b[0m arguments to this function are incorrect",
694 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m│\u001b[0m ",
695 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m expected `&mut Channel`, found `Channel`",
696 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m│\u001b[0m ",
697 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;68m╰\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m\u001b[38;5;68m─\u001b[0m help: consider mutably borrowing here: `&mut channel`",
698 | "\u001b[38;5;246m───╯\u001b[0m"
699 | ]
700 | },
701 | {
702 | "ename": "Error",
703 | "evalue": "`Vec` doesn't implement `std::fmt::Display`",
704 | "output_type": "error",
705 | "traceback": [
706 | "\u001b[31m[E0277] Error:\u001b[0m `Vec` doesn't implement `std::fmt::Display`",
707 | " \u001b[38;5;246m╭\u001b[0m\u001b[38;5;246m─\u001b[0m\u001b[38;5;246m[\u001b[0mcommand_59:1:1\u001b[38;5;246m]\u001b[0m",
708 | " \u001b[38;5;246m│\u001b[0m",
709 | " \u001b[38;5;246m2 │\u001b[0m \u001b[38;5;249mp\u001b[0m\u001b[38;5;249mr\u001b[0m\u001b[38;5;249mi\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249mt\u001b[0m\u001b[38;5;249ml\u001b[0m\u001b[38;5;249mn\u001b[0m\u001b[38;5;249m!\u001b[0m\u001b[38;5;249m(\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m{\u001b[0m\u001b[38;5;249m}\u001b[0m\u001b[38;5;249m\"\u001b[0m\u001b[38;5;249m,\u001b[0m\u001b[38;5;249m \u001b[0m\u001b[38;5;54mc\u001b[0m\u001b[38;5;54mh\u001b[0m\u001b[38;5;54ma\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54mn\u001b[0m\u001b[38;5;54me\u001b[0m\u001b[38;5;54ml\u001b[0m\u001b[38;5;54m.\u001b[0m\u001b[38;5;54mp\u001b[0m\u001b[38;5;54mr\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mo\u001b[0m\u001b[38;5;54mf\u001b[0m\u001b[38;5;249m)\u001b[0m\u001b[38;5;249m;\u001b[0m",
710 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m┬\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m ",
711 | " \u001b[38;5;246m ·\u001b[0m \u001b[38;5;54m╰\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m\u001b[38;5;54m─\u001b[0m `Vec` cannot be formatted with the default formatter",
712 | "\u001b[38;5;246m───╯\u001b[0m"
713 | ]
714 | }
715 | ],
716 | "source": [
717 | "let (fri_polys, fri_domains, fri_layers, fri_merkles) = fri_commit(cp, eval_domain, cp_eval, cp_merkle, channel);\n",
718 | "println!(\"{}\", channel.proof);"
719 | ]
720 | },
721 | {
722 | "cell_type": "code",
723 | "execution_count": null,
724 | "metadata": {},
725 | "outputs": [],
726 | "source": []
727 | }
728 | ],
729 | "metadata": {
730 | "kernelspec": {
731 | "display_name": "Rust",
732 | "language": "rust",
733 | "name": "rust"
734 | },
735 | "language_info": {
736 | "codemirror_mode": "rust",
737 | "file_extension": ".rs",
738 | "mimetype": "text/rust",
739 | "name": "Rust",
740 | "pygment_lexer": "rust",
741 | "version": ""
742 | },
743 | "vscode": {
744 | "interpreter": {
745 | "hash": "8d966b88690763694386749576545adb56f45130b41d03aad899141d4edbc5c3"
746 | }
747 | }
748 | },
749 | "nbformat": 4,
750 | "nbformat_minor": 4
751 | }
752 |
--------------------------------------------------------------------------------
/part4.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "markdown",
5 | "metadata": {},
6 | "source": [
7 | "*Copyright 2019 StarkWare Industries Ltd.
Licensed under the Apache License, Version 2.0 (the \"License\"). You may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.starkware.co/open-source-license/
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.*"
8 | ]
9 | },
10 | {
11 | "cell_type": "markdown",
12 | "metadata": {},
13 | "source": [
14 | "# Part 4: Query Phase"
15 | ]
16 | },
17 | {
18 | "cell_type": "markdown",
19 | "metadata": {},
20 | "source": [
21 | "- [Video Lecture (youtube)](https://www.youtube.com/watch?v=CxP28qM4tAc)\n",
22 | "- [Slides (PDF)](https://starkware.co/wp-content/uploads/2021/12/STARK101-Part4.pdf)\n",
23 | "\n",
24 | "### Load the Previous Session\n",
25 | "Run the next cell to load the variables we'll use in this part. Since it repeats everything done in previous parts - it will take a while to run."
26 | ]
27 | },
28 | {
29 | "cell_type": "code",
30 | "execution_count": 9,
31 | "metadata": {},
32 | "outputs": [
33 | {
34 | "name": "stdout",
35 | "output_type": "stream",
36 | "text": [
37 | "Success!\n"
38 | ]
39 | }
40 | ],
41 | "source": [
42 | ":dep stark101-rs = { path = \"stark101\" }\n",
43 | ":dep sha256 = \"1.1.2\"\n",
44 | "use stark101_rs::{field::FieldElement, channel::Channel, polynomial::{Polynomial, x}, merkle_tree::MerkleTree};\n",
45 | "use stark101_rs::parts::{part1, part3};\n",
46 | "\n",
47 | "let (_, _, _, _, _, _, _, f_eval, f_merkle, _) = part1();\n",
48 | "let (fri_polys, fri_domains, fri_layers, fri_merkles, _ch): (Vec, Vec>, Vec>, Vec, Channel) = part3();\n",
49 | "\n",
50 | "println!(\"Success!\");"
51 | ]
52 | },
53 | {
54 | "cell_type": "markdown",
55 | "metadata": {},
56 | "source": [
57 | "## Decommit on a Query\n",
58 | "\n",
59 | "Our goal in this part is to generate all the information needed for verifying the commitments of the three previous parts. In this part we write two functions:\n",
60 | "1. `decommit_on_fri_layers` - sends over the channel data showing that each FRI layer is consistent with the others, when sampled at a specified index.\n",
61 | "2. `decommit_on_query` - sends data required for decommiting on the trace and then calls `decommit_on_fri_layers`.
"
62 | ]
63 | },
64 | {
65 | "cell_type": "markdown",
66 | "metadata": {},
67 | "source": [
68 | "### Decommit on the FRI Layers\n",
69 | "Implement `decommit_on_fri_layers` function. The function gets an index and a channel, and sends over the channel the relevant data for verifying the correctness of the FRI layers. More specifically, it iterates over `fri_layers` and `fri_merkles` and in each iteration it sends the following data (in the stated order):\n",
70 | "1. The element of the FRI layer at the given index (using `fri_layers`).\n",
71 | "2. Its authentication path (using the corresponding Merkle tree from `fri_merkles`).\n",
72 | "3. The element's FRI sibling (i.e., if the element is $cp_i(x)$, then its sibling is $cp_i(-x)$, where $cp_i$ is the current layer's polynomial, and $x$ is an element from the current layer's domain). \n",
73 | "4. The authentication path of the element's sibling (using the same merkle tree).\n",
74 | "\n",
75 | "To get an authentication path of an element, use `get_authentication_path()` of the `MerkleTree` class, with the corresponding index each time. Note that the index of the element's sibling equals to (idx + $\\frac k 2$) mod $k$, where $k$ is the length of the relevant FRI layer.
\n",
76 | "Note that we do **not** send the authentication path for the element in the last layer. In the last layer, all the elements are equal, regardless of the query, as they are evaluations of a constant polynomial.\n",
77 | "\n",
78 | "*(Remember to convert non-string variables into string before sending over the channel.)*"
79 | ]
80 | },
81 | {
82 | "cell_type": "code",
83 | "execution_count": null,
84 | "metadata": {},
85 | "outputs": [],
86 | "source": [
87 | "// Fix this.\n",
88 | "fn decommit_on_fri_layers(idx: usize, channel: &mut Channel, fri_layers: Vec>, fri_merkles: Vec) {\n",
89 | " for layer, merkle in zip(fri_layers[:-1], fri_merkles[:-1]) {\n",
90 | " // Fix this: send elements and authentication pathes of all the FRI layers but the last one.\n",
91 | " channel.send(\"The element from the current layer\") // TODO\n",
92 | " channel.send(\"The authentication path for this element\") // TODO\n",
93 | " channel.send(\"The element\\'s sibling in the current layer\") // TODO\n",
94 | " channel.send(\"The sibling\\'s authentication path\") // TODO\n",
95 | " }\n",
96 | " // Send the element in the last FRI layer.\n",
97 | " channel.send(\"The last element\")\n",
98 | "}"
99 | ]
100 | },
101 | {
102 | "cell_type": "markdown",
103 | "metadata": {},
104 | "source": [
105 | "Solution:"
106 | ]
107 | },
108 | {
109 | "cell_type": "code",
110 | "execution_count": null,
111 | "metadata": {
112 | "tags": []
113 | },
114 | "outputs": [],
115 | "source": [
116 | "fn decommit_on_fri_layers(idx: usize, channel: &mut Channel, fri_layers: Vec>, fri_merkles: Vec) {\n",
117 | " for (layer, merkle) in zip(fri_layers[:-1], fri_merkles[:-1]) {\n",
118 | " let length = layer.len();\n",
119 | " let idx = idx % length;\n",
120 | " let sib_idx = (idx + length / 2) % length \n",
121 | " channel.send(layer[idx].to_string());\n",
122 | " channel.send(merkle.get_authentication_path(idx));\n",
123 | " channel.send(str(layer[sib_idx]));\n",
124 | " channel.send(str(merkle.get_authentication_path(sib_idx)));\n",
125 | " }\n",
126 | " channel.send(str(fri_layers[-1][0]))\n",
127 | "} "
128 | ]
129 | },
130 | {
131 | "cell_type": "markdown",
132 | "metadata": {},
133 | "source": [
134 | "Test your code:"
135 | ]
136 | },
137 | {
138 | "cell_type": "code",
139 | "execution_count": null,
140 | "metadata": {},
141 | "outputs": [],
142 | "source": [
143 | "// Test against a precomputed hash.\n",
144 | "let mut test_channel = Channel();\n",
145 | "for query in vec![7527, 8168, 1190, 2668, 1262, 1889, 3828, 5798, 396, 2518] {\n",
146 | " decommit_on_fri_layers(query, &mut test_channel, fri_layers.clone());\n",
147 | "}\n",
148 | "assert_eq!(test_channel.state, \"ad4fe9aaee0fbbad0130ae0fda896393b879c5078bf57d6c705ec41ce240861b\", \"State of channel is wrong.\");\n",
149 | "println!(\"Success!\");\n"
150 | ]
151 | },
152 | {
153 | "cell_type": "markdown",
154 | "metadata": {},
155 | "source": [
156 | "### Decommit on the Trace Polynomial\n",
157 | "To prove that indeed the FRI layers we decommit on were generated from evaluation of the composition polynomial, we must also send:\n",
158 | "1. The value $f(x)$ with its authentication path.\n",
159 | "2. The value $f(gx)$ with its authentication path.\n",
160 | "3. The value $f(g^2x)$ with its authentication path.
\n",
161 | "The verifier, knowing the random coefficients of the composition polynomial, can compute its evaluation at $x$, and compare it with the first element sent from the first FRI layer.\n",
162 | "\n",
163 | "The function `decommit_on_query` should therefore send the above (1, 2, and 3) over the channel, and then call `decommit_on_fri_layers`.
\n",
164 | "\n",
165 | "Importantly, even though $x, gx, g^2x$ are consecutive elements (modulo the group size $|G|$) in the trace, the evaluations of `f_eval` in these points are actually 8 elements apart. The reason for this is that we \"blew up\" the trace to 8 times its size in part I, to obtain a Reed Solomon codeword.\n",
166 | "\n",
167 | "*Reminder: `f_eval` is the evaluation of the composition polynomial, and `f_merkle` is the corresponding Merkle tree.*"
168 | ]
169 | },
170 | {
171 | "cell_type": "code",
172 | "execution_count": null,
173 | "metadata": {},
174 | "outputs": [],
175 | "source": [
176 | "fn decommit_on_query(idx: usize, channel: &mut Channel, fri_layers: Vec>) {\n",
177 | " // Send elements and authentication pathes for f(x), f(gx) and f(g^2x) over the channel. \n",
178 | " channel.send(\"f(x)\"); // TODO\n",
179 | " channel.send(\"f(x)\\'s authentication path\"); // TODO\n",
180 | " channel.send(\"f(gx)\"); // TODO\n",
181 | " channel.send(\"f(gx)\\'s authentication path\"); // TODO\n",
182 | " channel.send(\"f(g^2x)\"); // TODO\n",
183 | " channel.send(\"f(g^2x)\\'s authentication path\"); // TODO\n",
184 | " decommit_on_fri_layers(idx, &mut channel, fri_layers) // No need to fix this line.\n",
185 | "}"
186 | ]
187 | },
188 | {
189 | "cell_type": "markdown",
190 | "metadata": {},
191 | "source": [
192 | "Solution:"
193 | ]
194 | },
195 | {
196 | "cell_type": "code",
197 | "execution_count": null,
198 | "metadata": {
199 | "tags": []
200 | },
201 | "outputs": [],
202 | "source": [
203 | "fn decommit_on_query(idx: usize, channel: &mut Channel, fri_layers: Vec>) {\n",
204 | " let f_eval_len = f_eval.len();\n",
205 | " assert!(idx + 16 < f_eval.len(), \"query index: {idx} is out of range. Length of layer: {f_eval_len}.\");\n",
206 | " channel.send(f_eval[idx].to_string()); // f(x).\n",
207 | " channel.send(f_merkle.get_authentication_path(idx).to_string())); // auth path for f(x).\n",
208 | " channel.send(f_eval[idx + 8].to_string()); // f(gx).\n",
209 | " channel.send(f_merkle.get_authentication_path(idx + 8).to_string()); // auth path for f(gx).\n",
210 | " channel.send(f_eval[idx + 16].to_string()); // f(g^2x).\n",
211 | " channel.send(f_merkle.get_authentication_path(idx + 16).to_string()); // auth path for f(g^2x).\n",
212 | " decommit_on_fri_layers(idx, channel, fri_layers);\n",
213 | "}"
214 | ]
215 | },
216 | {
217 | "cell_type": "markdown",
218 | "metadata": {},
219 | "source": [
220 | "Test your code:"
221 | ]
222 | },
223 | {
224 | "cell_type": "code",
225 | "execution_count": null,
226 | "metadata": {},
227 | "outputs": [],
228 | "source": [
229 | "// Test against a precomputed hash.\n",
230 | "let mut test_channel = Channel();\n",
231 | "for query in vec![8134, 1110, 1134, 6106, 7149, 4796, 144, 4738, 957] {\n",
232 | " decommit_on_query(query, test_channel)\n",
233 | "}\n",
234 | "assert_eq!(test_channel.state, \"16a72acce8d10ffb318f8f5cd557930e38cdba236a40439c9cf04aaf650cfb96\", \"State of channel is wrong.\");\n",
235 | "println!(\"Success!\");"
236 | ]
237 | },
238 | {
239 | "cell_type": "markdown",
240 | "metadata": {},
241 | "source": [
242 | "### Decommit on a Set of Queries\n",
243 | "To finish the proof, the prover gets a set of random queries from the channel, i.e., indices between 0 to 8191, and decommits on each query.\n",
244 | "\n",
245 | "Use the function that you just implemented `decommit_on_query()`, and `Channel.receive_random_int` to generate 3 random queries and decommit on each."
246 | ]
247 | },
248 | {
249 | "cell_type": "code",
250 | "execution_count": null,
251 | "metadata": {},
252 | "outputs": [],
253 | "source": [
254 | "// Fix this.\n",
255 | "fn decommit_fri(channel: &mut Channel) {\n",
256 | " for query in 0..3 {\n",
257 | " todo!(); // Get a random index from the channel and send the corresponding decommitment.\n",
258 | " }\n",
259 | "}"
260 | ]
261 | },
262 | {
263 | "cell_type": "markdown",
264 | "metadata": {},
265 | "source": [
266 | "Solution:"
267 | ]
268 | },
269 | {
270 | "cell_type": "code",
271 | "execution_count": null,
272 | "metadata": {
273 | "tags": []
274 | },
275 | "outputs": [],
276 | "source": [
277 | "fn decommit_fri(channel: &mut Channel) {\n",
278 | " for query in 0..3 {\n",
279 | " // Get a random index from the verifier and send the corresponding decommitment.\n",
280 | " decommit_on_query(channel.receive_random_int(0, 8191-16), channel);\n",
281 | " }\n",
282 | "}"
283 | ]
284 | }
285 | ],
286 | "metadata": {
287 | "kernelspec": {
288 | "display_name": "Rust",
289 | "language": "rust",
290 | "name": "rust"
291 | },
292 | "language_info": {
293 | "codemirror_mode": "rust",
294 | "file_extension": ".rs",
295 | "mimetype": "text/rust",
296 | "name": "Rust",
297 | "pygment_lexer": "rust",
298 | "version": ""
299 | },
300 | "vscode": {
301 | "interpreter": {
302 | "hash": "8d966b88690763694386749576545adb56f45130b41d03aad899141d4edbc5c3"
303 | }
304 | }
305 | },
306 | "nbformat": 4,
307 | "nbformat_minor": 4
308 | }
309 |
--------------------------------------------------------------------------------
/rust-toolchain:
--------------------------------------------------------------------------------
1 | nightly
--------------------------------------------------------------------------------
/stark101/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "stark101-rs"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [dependencies]
9 | rand = "0.8.5"
10 | itertools = "0.10.5"
11 | sha256 = "1.1.2"
12 | primitive-types = "0.12.1"
13 | rs_merkle = "1.2"
14 | hex = "0.4"
15 |
--------------------------------------------------------------------------------
/stark101/src/channel.rs:
--------------------------------------------------------------------------------
1 | use crate::field::FieldElement;
2 | use primitive_types::U256;
3 | use sha256;
4 | /// A Channel instance can be used by a prover or a verifier to preserve the semantics of an
5 | /// interactive proof system, while under the hood it is in fact non-interactive, and uses Sha256
6 | /// to generate randomness when this is required.
7 | /// It allows writing string-form data to it, and reading either random integers of random
8 | /// FieldElements from it.
9 | #[derive(Debug, Clone)]
10 | pub struct Channel {
11 | pub proof: Vec,
12 | pub state: String,
13 | }
14 |
15 | impl Channel {
16 | pub fn new() -> Channel {
17 | Channel {
18 | state: "0".to_string(),
19 | proof: vec![],
20 | }
21 | }
22 |
23 | pub fn send(&mut self, s: String) {
24 | let current_state = self.state.clone();
25 | self.state = sha256::digest(current_state + &s);
26 | self.proof.push(format!("{s}"));
27 | }
28 |
29 | /// Emulates a random field element sent by the verifier.
30 | pub fn receive_random_field_element(&mut self) -> FieldElement {
31 | let num = self.receive_random_int(0, FieldElement::k_modulus() - 1, false);
32 | self.proof.push(format!("{num}"));
33 | FieldElement::new(num)
34 | }
35 |
36 | /// Emulates a random integer sent by the verifier in the range [min, max]
37 | /// (including min and max).
38 | pub fn receive_random_int(&mut self, min: usize, max: usize, show_in_proof: bool) -> usize {
39 | // Note that when the range is close to 2^256 this does not emit a uniform distribution,
40 | // even if sha256 is uniformly distributed.
41 | // It is, however, close enough for this tutorial's purposes.
42 | let num = (U256::from_str_radix(&self.state, 16).unwrap() + min) % (max - min + 1);
43 | let current_state = self.state.clone();
44 | self.state = sha256::digest(current_state);
45 | if show_in_proof {
46 | self.proof.push(format!("{num}"));
47 | }
48 | num.as_usize()
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/stark101/src/field.rs:
--------------------------------------------------------------------------------
1 | use rand::Rng;
2 |
3 | /// An implementation of field elements from F_(3 * 2**30 + 1).
4 | #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
5 | pub struct FieldElement(pub usize);
6 |
7 | impl FieldElement {
8 | pub fn new(value: usize) -> Self {
9 | FieldElement(value % FieldElement::k_modulus())
10 | }
11 |
12 | pub fn k_modulus() -> usize {
13 | 3 * 2usize.pow(30) + 1
14 | }
15 |
16 | pub fn generator() -> Self {
17 | FieldElement(5)
18 | }
19 |
20 | /// Obtains the zero element of the field.
21 | pub fn zero() -> Self {
22 | FieldElement(0)
23 | }
24 |
25 | /// Obtains the unit element of the field.
26 | pub fn one() -> Self {
27 | FieldElement(1)
28 | }
29 |
30 | pub fn inverse(&self) -> Self {
31 | let (mut t, mut new_t) = (0, 1);
32 | let (mut r, mut new_r) = (FieldElement::k_modulus() as i128, self.0 as i128);
33 | while new_r != 0 {
34 | let quotient = r / new_r;
35 | (t, new_t) = (new_t, t - (quotient * new_t));
36 | (r, new_r) = (new_r, r - quotient * new_r);
37 | }
38 | assert!(r == 1);
39 | t.into()
40 | }
41 |
42 | pub fn pow(&self, n: usize) -> Self {
43 | let mut n = n;
44 | let mut current_pow = self.to_owned();
45 | let mut res = FieldElement::one();
46 | while n > 0 {
47 | if n % 2 != 0 {
48 | res *= current_pow;
49 | }
50 | n = n / 2;
51 | current_pow *= current_pow;
52 | }
53 | res
54 | }
55 |
56 | /// Naively checks that the element is of order n by raising it to all powers up to n, checking
57 | /// that the element to the n-th power is the unit, but not so for any k < n.
58 | pub fn is_order(&self, n: usize) -> bool {
59 | assert!(n >= 1);
60 | let mut h = FieldElement(1);
61 | for _ in 1..n {
62 | h *= self;
63 | if h == FieldElement::one() {
64 | return false;
65 | }
66 | }
67 | h * self == FieldElement::one()
68 | }
69 |
70 | /// Generates a random FieldElement.
71 | pub fn random_element(excluded_elements: &[FieldElement]) -> Self {
72 | let mut rng = rand::thread_rng();
73 | let mut fe = FieldElement::new(rng.gen::());
74 | while excluded_elements.contains(&fe) {
75 | fe = FieldElement::new(rng.gen::());
76 | }
77 | fe
78 | }
79 | }
80 |
81 | impl From for FieldElement {
82 | fn from(value: usize) -> Self {
83 | FieldElement::new(value)
84 | }
85 | }
86 |
87 | impl From for usize {
88 | fn from(value: FieldElement) -> Self {
89 | value.0
90 | }
91 | }
92 |
93 | impl From for FieldElement {
94 | fn from(value: i128) -> Self {
95 | let value_mod_p = if value > 0 {
96 | value % (FieldElement::k_modulus() as i128)
97 | } else {
98 | value + FieldElement::k_modulus() as i128
99 | };
100 | FieldElement::new(value_mod_p.try_into().unwrap())
101 | }
102 | }
103 |
104 | impl PartialEq for FieldElement {
105 | fn eq(&self, other: &usize) -> bool {
106 | self == &FieldElement::new(*other)
107 | }
108 | }
109 |
110 | impl std::ops::Add for FieldElement {
111 | type Output = FieldElement;
112 |
113 | fn add(self, rhs: Self) -> Self::Output {
114 | FieldElement::new(self.0 + rhs.0)
115 | }
116 | }
117 |
118 | impl std::ops::Add for &FieldElement {
119 | type Output = FieldElement;
120 |
121 | fn add(self, rhs: Self) -> Self::Output {
122 | FieldElement::new(self.0 + rhs.0)
123 | }
124 | }
125 |
126 | impl std::ops::AddAssign for FieldElement {
127 | fn add_assign(&mut self, rhs: Self) {
128 | *self = FieldElement::new(self.0 + rhs.0)
129 | }
130 | }
131 |
132 | impl std::ops::Mul for FieldElement {
133 | type Output = FieldElement;
134 |
135 | fn mul(self, rhs: Self) -> Self::Output {
136 | FieldElement::new(self.0 * rhs.0)
137 | }
138 | }
139 |
140 | impl std::ops::Mul<&FieldElement> for FieldElement {
141 | type Output = FieldElement;
142 |
143 | fn mul(self, rhs: &Self) -> Self::Output {
144 | FieldElement::new(self.0 * rhs.0)
145 | }
146 | }
147 |
148 | impl std::ops::MulAssign for FieldElement {
149 | fn mul_assign(&mut self, rhs: Self) {
150 | *self = FieldElement::new(self.0 * rhs.0)
151 | }
152 | }
153 |
154 | impl std::ops::MulAssign<&FieldElement> for FieldElement {
155 | fn mul_assign(&mut self, rhs: &Self) {
156 | *self = FieldElement::new(self.0 * rhs.0)
157 | }
158 | }
159 |
160 | impl std::ops::Sub for FieldElement {
161 | type Output = FieldElement;
162 |
163 | fn sub(self, rhs: Self) -> Self::Output {
164 | let sub_result = self.0 as i128 - rhs.0 as i128;
165 | sub_result.into()
166 | }
167 | }
168 |
169 | impl std::ops::Sub<&FieldElement> for FieldElement {
170 | type Output = FieldElement;
171 |
172 | fn sub(self, rhs: &Self) -> Self::Output {
173 | FieldElement::new(self.0 - rhs.0)
174 | }
175 | }
176 |
177 | impl std::ops::Div for FieldElement {
178 | type Output = FieldElement;
179 |
180 | fn div(self, rhs: Self) -> Self::Output {
181 | self * rhs.inverse()
182 | }
183 | }
184 |
185 | impl std::ops::Div for FieldElement {
186 | type Output = FieldElement;
187 |
188 | fn div(self, rhs: usize) -> Self::Output {
189 | self * FieldElement::new(rhs).inverse()
190 | }
191 | }
192 |
193 | impl std::ops::Neg for FieldElement {
194 | type Output = FieldElement;
195 |
196 | fn neg(self) -> Self::Output {
197 | FieldElement::zero() - self
198 | }
199 | }
200 |
201 | #[cfg(test)]
202 | mod tests {
203 | use super::FieldElement;
204 |
205 | #[test]
206 | fn inverse_test() {
207 | let x = FieldElement::new(2);
208 | let x_inv = x.inverse();
209 |
210 | assert_eq!(FieldElement::one(), x * x_inv)
211 | }
212 |
213 | #[test]
214 | fn test_field_wrap() {
215 | // Check pow, mul, and the modular operations
216 | let t = FieldElement(2).pow(30) * FieldElement(3) + FieldElement::one();
217 | assert!(t == FieldElement::zero())
218 | }
219 |
220 | #[test]
221 | fn test_field_div() {
222 | for _ in 1..10000 {
223 | let t = FieldElement::random_element(&[FieldElement::zero()]);
224 | let t_inv = FieldElement::one() / t;
225 | assert!(t_inv == t.inverse());
226 | assert!(t_inv * t == FieldElement::one());
227 | }
228 | }
229 | }
230 |
--------------------------------------------------------------------------------
/stark101/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![feature(unboxed_closures)]
2 | #![feature(fn_traits)]
3 | pub mod channel;
4 | pub mod field;
5 | pub mod merkle_tree;
6 | pub mod parts;
7 | pub mod polynomial;
8 |
--------------------------------------------------------------------------------
/stark101/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() {
2 | println!("Hello, world!");
3 | }
4 |
--------------------------------------------------------------------------------
/stark101/src/merkle_tree.rs:
--------------------------------------------------------------------------------
1 | use crate::field::FieldElement;
2 | use rs_merkle::algorithms::Sha256;
3 | use rs_merkle::{self, Hasher};
4 |
5 | pub struct MerkleTree {
6 | inner: rs_merkle::MerkleTree,
7 | }
8 |
9 | impl MerkleTree {
10 | pub fn new(data: Vec) -> MerkleTree {
11 | let hashed_data: Vec<[u8; 32]> = data
12 | .into_iter()
13 | .map(|d| Sha256::hash(&d.0.to_be_bytes()))
14 | .collect();
15 |
16 | let inner =
17 | rs_merkle::MerkleTree::::from_leaves(&hashed_data);
18 |
19 | MerkleTree { inner }
20 | }
21 |
22 | pub fn root(&self) -> String {
23 | self.inner.root_hex().unwrap()
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/stark101/src/parts.rs:
--------------------------------------------------------------------------------
1 | use crate::{
2 | channel::{Channel, self}, field::FieldElement, merkle_tree::MerkleTree, polynomial::Polynomial,
3 | };
4 |
5 | pub fn part1() -> (
6 | Vec,
7 | FieldElement,
8 | Vec,
9 | FieldElement,
10 | Vec,
11 | Vec,
12 | Polynomial,
13 | Vec,
14 | MerkleTree,
15 | Channel,
16 | ) {
17 | let mut t = vec![FieldElement::one(), FieldElement::new(3141592)];
18 | let mut n = 2usize;
19 | while t.len() < 1023 {
20 | t.push(t[n - 2] * t[n - 2] + t[n - 1] * t[n - 1]);
21 | n += 1;
22 | }
23 | let g = FieldElement::generator().pow(3 * 2usize.pow(20));
24 | let points: Vec = (0..1024).into_iter().map(|i| g.pow(i)).collect();
25 | let w = FieldElement::generator();
26 | let exp = (2usize.pow(30) * 3) / 8192;
27 | let h_gen = w.pow(exp);
28 | let h: Vec = (0..8192).into_iter().map(|i| h_gen.pow(i)).collect();
29 | let domain: Vec = h.clone().into_iter().map(|x| w * x).collect();
30 | let x_values: Vec = points.clone().into_iter().rev().skip(1).rev().collect();
31 | let p: Polynomial = Polynomial::interpolate(&x_values, &t);
32 | let ev: Vec = domain
33 | .clone()
34 | .into_iter()
35 | .map(|d| p.clone().eval(d))
36 | .collect();
37 | let mt = MerkleTree::new(ev.clone());
38 | let ch = Channel::new();
39 | (t, g, points, h_gen, h, domain, p, ev, mt, ch)
40 | }
41 |
42 |
43 | pub fn part2() -> (Polynomial, Vec, MerkleTree, Channel, Vec) {
44 | let (_t, _g, points, _h_gen, _h, domain, p, _ev, _mt, ch) = part1();
45 | let numer0 = p.clone() - Polynomial::new(&[FieldElement::one()]);
46 | let denom0 = Polynomial::gen_linear_term(FieldElement::one());
47 | let (q0, _r0) = numer0.qdiv(denom0);
48 | let numer1 = p.clone() - Polynomial::new(&[FieldElement::new(2338775057)]);
49 | let denom1 = Polynomial::gen_linear_term(points[1022]);
50 | let (q1, _r1) = numer1.qdiv(denom1);
51 | let inner_poly0 = Polynomial::new(&[FieldElement::zero(), points[2]]);
52 | let final0 = p.clone().compose(inner_poly0);
53 |
54 | let inner_poly1 = Polynomial::new(&[FieldElement::zero(), points[1]]);
55 | let composition = p.clone().compose(inner_poly1);
56 | let final1 = composition.clone() * composition;
57 | let final2 = p.clone() * p;
58 | let numer2 = final0 - final1 - final2;
59 | let mut coef = vec![FieldElement::one()];
60 | for _ in 0..1023 {
61 | coef.push(FieldElement::zero());
62 | }
63 | coef.push(FieldElement(FieldElement::k_modulus() - 1));
64 | let numerator_of_denom2 = Polynomial::new(&coef);
65 | let factor0 = Polynomial::gen_linear_term(points[1021]);
66 | let factor1 = Polynomial::gen_linear_term(points[1022]);
67 | let factor2 = Polynomial::gen_linear_term(points[1023]);
68 | let denom_of_denom2 = factor0 * factor1 * factor2;
69 | let (denom2, _r_denom2) = numerator_of_denom2.qdiv(denom_of_denom2);
70 | let (q2, _r2) = numer2.qdiv(denom2);
71 | let mut ch_mut = ch.clone();
72 | let cp0 = q0 * ch_mut.receive_random_field_element();
73 | let cp1 = q1 * ch_mut.receive_random_field_element();
74 | let cp2 = q2 * ch_mut.receive_random_field_element();
75 |
76 | let cp = cp0 + cp1 + cp2;
77 | let cp_ev: Vec = domain.clone().into_iter().map(|d| cp(d)).collect();
78 | let cp_mt = MerkleTree::new(cp_ev.clone());
79 | ch_mut.send(cp_mt.root());
80 |
81 | (cp, cp_ev, cp_mt, ch_mut, domain)
82 | }
83 |
84 |
85 | fn next_fri_domain(fri_domain: Vec) -> Vec {
86 | let fri_domain_len = fri_domain.len();
87 | fri_domain.into_iter().take(fri_domain_len / 2).map(|x| x.pow(2)).collect()
88 | }
89 |
90 | fn next_fri_polynomial(poly: Polynomial, beta: FieldElement) -> Polynomial {
91 | let odd_coefficients: Vec = poly.0.clone().into_iter().skip(1).step_by(2).collect();
92 | let even_coefficients: Vec = poly.0.into_iter().step_by(2).collect();
93 | let odd = Polynomial::new(&odd_coefficients) * beta;
94 | let even = Polynomial::new(&even_coefficients);
95 | odd + even
96 | }
97 |
98 | fn next_fri_layer(poly: Polynomial, domain: Vec, beta: FieldElement) -> (Polynomial, Vec, Vec) {
99 | let next_poly = next_fri_polynomial(poly, beta);
100 | let next_domain = next_fri_domain(domain);
101 | let next_layer: Vec = next_domain.clone().into_iter().map(|x| next_poly(x)).collect();
102 | (next_poly, next_domain, next_layer)
103 | }
104 |
105 | fn fri_commit(cp: Polynomial, domain: Vec, cp_eval: Vec, cp_merkle: MerkleTree, channel: &mut Channel) -> (Vec, Vec>, Vec>, Vec, Channel) {
106 | let mut fri_polys: Vec = vec![cp];
107 | let mut fri_domains: Vec> = vec![domain];
108 | let mut fri_layers: Vec> = vec![cp_eval];
109 | let mut fri_merkles: Vec = vec![cp_merkle];
110 | while fri_polys.last().unwrap().degree() > 0 {
111 | let beta = channel.receive_random_field_element();
112 | let last_poly = fri_polys.last().unwrap().clone();
113 | let last_domain = fri_domains.last().unwrap().clone();
114 | let (next_poly, next_domain, next_layer) = next_fri_layer(last_poly, last_domain, beta);
115 | fri_polys.push(next_poly.clone());
116 | fri_domains.push(next_domain.clone());
117 | fri_layers.push(next_layer.clone());
118 | fri_merkles.push(MerkleTree::new(next_layer));
119 | channel.send(fri_merkles.last().unwrap().root())
120 | }
121 | channel.send(fri_polys.last().unwrap().0[0].0.to_string());
122 |
123 | (fri_polys, fri_domains, fri_layers, fri_merkles, channel.clone())
124 | }
125 |
126 | pub fn part3() -> (Vec, Vec>, Vec>, Vec, Channel) {
127 | let (cp, cp_ev, cp_mt, channel, domain) = part2();
128 | let mut channel = channel.clone();
129 | fri_commit(cp, domain, cp_ev, cp_mt, &mut channel)
130 | }
--------------------------------------------------------------------------------
/stark101/src/polynomial.rs:
--------------------------------------------------------------------------------
1 | use crate::field::FieldElement;
2 | use itertools::{enumerate, EitherOrBoth, Itertools};
3 |
4 | pub fn x() -> Polynomial {
5 | Polynomial::x()
6 | }
7 |
8 | /// Represents a polynomial over FieldElement.
9 | #[derive(Debug, PartialEq, Clone)]
10 | pub struct Polynomial(pub Vec);
11 |
12 | impl Polynomial {
13 | /// Creates a new Polynomial with the given coefficients.
14 | /// Internally storing the coefficients in self.poly, least-significant (i.e. free term)
15 | /// first, so 9 - 3x^2 + 19x^5 is represented internally by the vector [9, 0, -3, 0, 0, 19].
16 | pub fn new(coefficients: &[FieldElement]) -> Self {
17 | Polynomial(coefficients.into())
18 | }
19 |
20 | /// Returns the polynomial x.
21 | pub fn x() -> Self {
22 | Polynomial(vec![FieldElement::zero(), FieldElement::one()])
23 | }
24 |
25 | /// Constructs the monomial coefficient * x^degree.
26 | pub fn monomial(degree: usize, coefficient: FieldElement) -> Self {
27 | let mut coefficients = [FieldElement::zero()].repeat(degree);
28 | coefficients.push(coefficient);
29 | Polynomial::new(&coefficients)
30 | }
31 |
32 | /// Computes the product of the given polynomials.
33 | pub fn prod(values: &[Polynomial]) -> Polynomial {
34 | let len_values = values.len();
35 | if len_values == 0 {
36 | return Polynomial(vec![FieldElement::one()]);
37 | };
38 | if len_values == 1 {
39 | return values.first().unwrap().to_owned().into();
40 | };
41 | let prod_left = values
42 | .into_iter()
43 | .take(len_values / 2)
44 | .map(ToOwned::to_owned)
45 | .collect_vec();
46 | let prod_right = values
47 | .into_iter()
48 | .skip(len_values / 2)
49 | .map(ToOwned::to_owned)
50 | .collect_vec();
51 | Self::prod(&prod_left) * Self::prod(&prod_right)
52 | }
53 |
54 | /// Generates the polynomial (x-p) for a given point p.
55 | pub fn gen_linear_term(point: FieldElement) -> Self {
56 | Polynomial::new(&[FieldElement::zero() - point, FieldElement::one()])
57 | }
58 |
59 | pub fn modulo(&self, other: Polynomial) -> Polynomial {
60 | self.qdiv(other).1
61 | }
62 |
63 | /// The polynomials are represented by a list so the degree is the length of the list minus the
64 | /// number of trailing zeros (if they exist) minus 1.
65 | /// This implies that the degree of the zero polynomial will be -1.
66 | pub fn degree(&self) -> isize {
67 | Self::trim_trailing_zeros(&self.0).len() as isize - 1
68 | }
69 |
70 | fn remove_trailing_elements(
71 | elements: &[FieldElement],
72 | element_to_remove: &FieldElement,
73 | ) -> Vec {
74 | let it = elements
75 | .into_iter()
76 | .rev()
77 | .skip_while(|x| *x == element_to_remove)
78 | .map(Clone::clone);
79 | let mut v = it.collect::>();
80 | v.reverse();
81 | v
82 | }
83 |
84 | fn scalar_operation(
85 | elements: &[FieldElement],
86 | operation: F,
87 | scalar: impl Into,
88 | ) -> Vec
89 | where
90 | F: Fn(FieldElement, FieldElement) -> FieldElement,
91 | {
92 | let value: FieldElement = scalar.into();
93 | elements.into_iter().map(|e| operation(*e, value)).collect()
94 | }
95 |
96 | /// Removes zeros from the end of a list.
97 | fn trim_trailing_zeros(p: &[FieldElement]) -> Vec {
98 | Self::remove_trailing_elements(p, &FieldElement::zero())
99 | }
100 |
101 | fn two_list_tuple_operation(
102 | l1: &[FieldElement],
103 | l2: &[FieldElement],
104 | operation: F,
105 | fill_value: FieldElement,
106 | ) -> Vec
107 | where
108 | F: Fn(FieldElement, FieldElement) -> FieldElement,
109 | {
110 | l1.into_iter()
111 | .zip_longest(l2)
112 | .map(|x| match x {
113 | EitherOrBoth::Both(e1, e2) => operation(e1.to_owned(), e2.to_owned()),
114 | EitherOrBoth::Left(e) => operation(e.to_owned(), fill_value),
115 | EitherOrBoth::Right(e) => operation(e.to_owned(), fill_value),
116 | })
117 | .collect()
118 | }
119 |
120 | /// Returns the coefficient of x^n
121 | pub fn get_nth_degree_coefficient(&self, n: usize) -> FieldElement {
122 | if n > self.degree() as _ {
123 | FieldElement::zero()
124 | } else {
125 | self.0[n]
126 | }
127 | }
128 |
129 | /// Multiplies polynomial by a scalar.
130 | pub fn scalar_mul(&self, scalar: usize) -> Self {
131 | Polynomial(Self::scalar_operation(&self.0, |x, y| x * y, scalar))
132 | }
133 |
134 | /// Evaluates the polynomial at the given point using Horner evaluation.
135 | pub fn eval(&self, point: impl Into) -> FieldElement {
136 | let point: FieldElement = point.into();
137 | let mut val = FieldElement::zero();
138 | for coef in self.0.clone().into_iter().rev() {
139 | val = val * point + coef;
140 | }
141 | val
142 | }
143 |
144 | /// Calculates self^other using repeated squaring.
145 | pub fn pow(&self, other: usize) -> Self {
146 | let mut other = other;
147 | let mut res = Polynomial(vec![FieldElement::one()]);
148 | let mut current = self.to_owned();
149 | loop {
150 | if other % 2 != 0 {
151 | res = res * current.to_owned();
152 | }
153 | other >>= 1;
154 | if other == 0 {
155 | break;
156 | }
157 | current = current.to_owned() * current;
158 | }
159 | res
160 | }
161 |
162 | /// Given the x_values for evaluating some polynomials,
163 | /// it computes part of the lagrange polynomials required to interpolate a polynomial over this domain.
164 | pub fn calculate_lagrange_polynomials(x_values: &[FieldElement]) -> Vec {
165 | let mut lagrange_polynomials = vec![];
166 | let monomials = x_values
167 | .into_iter()
168 | .map(|x| Self::monomial(1, FieldElement::one()) - Self::monomial(0, *x))
169 | .collect_vec();
170 | let numerator = Self::prod(&monomials);
171 | for j in 0..(x_values.len()) {
172 | // In the denominator, we have:
173 | // (x_j-x_0)(x_j-x_1)...(x_j-x_{j-1})(x_j-x_{j+1})...(x_j-x_{len(X)-1})
174 | let denominator_values = enumerate(x_values)
175 | .filter(|(i, _)| *i != j)
176 | .map(|(_, x)| {
177 | let poly: Polynomial = x_values[j].into();
178 | let x_poly: Polynomial = (*x).into();
179 | poly - x_poly
180 | })
181 | .collect_vec();
182 | let denominator = Polynomial::prod(&denominator_values);
183 | // Numerator is a bit more complicated, since we need to compute a poly multiplication here.
184 | // Similarly to the denominator, we have:
185 | // (x-x_0)(x-x_1)...(x-x_{j-1})(x-x_{j+1})...(x-x_{len(X)-1})
186 | let (cur_poly, _) = numerator.qdiv(monomials[j].clone() * denominator);
187 | lagrange_polynomials.push(cur_poly);
188 | }
189 |
190 | lagrange_polynomials
191 | }
192 |
193 | /// Interpolate the polynomials given a set of y_values.
194 | /// - y_values: y coordinates of the points.
195 | /// - lagrange_polynomials: the polynomials obtained from calculate_lagrange_polynomials.
196 | ///
197 | /// Returns the interpolated polynomial.
198 | pub fn interpolate_poly_lagrange(
199 | y_values: &[FieldElement],
200 | lagrange_polynomials: Vec,
201 | ) -> Self {
202 | let mut poly = Polynomial(vec![]);
203 | for (j, y_value) in enumerate(y_values) {
204 | poly = poly + lagrange_polynomials[j].scalar_mul((*y_value).into());
205 | }
206 | poly
207 | }
208 |
209 | /// Returns q, r the quotient and remainder polynomials respectively, such that
210 | /// f = q * g + r, where deg(r) < deg(g).
211 | /// * Assert that g is not the zero polynomial.
212 | pub fn qdiv(&self, other: impl Into) -> (Polynomial, Polynomial) {
213 | let other_poly: Polynomial = other.into();
214 | let other_elems = Polynomial::trim_trailing_zeros(&other_poly.0);
215 | assert!(!other_elems.is_empty(), "Dividing by zero polynomial.");
216 | let self_elems = Polynomial::trim_trailing_zeros(&self.0);
217 | if self_elems.is_empty() {
218 | return (Polynomial(vec![]), Polynomial(vec![]));
219 | }
220 |
221 | let mut rem = self_elems.clone();
222 | let mut degree_difference = rem.len() as isize - other_elems.len() as isize;
223 | let mut quotient = if degree_difference > 0 {
224 | vec![FieldElement::zero()]
225 | .repeat((degree_difference + 1) as usize)
226 | .to_vec()
227 | } else {
228 | vec![FieldElement::zero()]
229 | };
230 | while degree_difference >= 0 {
231 | let tmp = rem.last().unwrap().to_owned() * other_elems.last().unwrap().inverse();
232 | quotient[degree_difference as usize] = quotient[degree_difference as usize] + tmp;
233 | let mut last_non_zero = degree_difference as isize - 1;
234 | for (i, coef) in enumerate(other_elems.clone()) {
235 | let k = i + degree_difference as usize;
236 | rem[k] = rem[k] - (tmp * coef);
237 | if rem[k] != FieldElement::zero() {
238 | last_non_zero = k as isize
239 | }
240 | }
241 | // Eliminate trailing zeroes (i.e. make r end with its last non-zero coefficient).
242 | rem = rem.into_iter().take((last_non_zero + 1) as usize).collect();
243 | degree_difference = rem.len() as isize - other_elems.len() as isize;
244 | }
245 |
246 | (
247 | Polynomial(Self::trim_trailing_zeros("ient)),
248 | Polynomial(rem),
249 | )
250 | }
251 |
252 | /// Returns a polynomial of degree < len(x_values) that evaluates to y_values[i] on x_values[i] for all i.
253 | pub fn interpolate(x_values: &[FieldElement], y_values: &[FieldElement]) -> Polynomial {
254 | assert!(x_values.len() == y_values.len());
255 | let lp = Self::calculate_lagrange_polynomials(x_values);
256 | Self::interpolate_poly_lagrange(y_values, lp)
257 | }
258 |
259 | // Composes this polynomial with `other`.
260 | // Example:
261 | // f = x().pow(2) + x()
262 | // g = x() + 1
263 | // f.compose(g) == (2 + x()*3 + x().pow(2))
264 | pub fn compose(&self, other: impl Into) -> Polynomial {
265 | let other_poly: Polynomial = other.into();
266 | let mut res = Polynomial(vec![]);
267 | for coef in self.0.clone().into_iter().rev() {
268 | res = (res * other_poly.clone()) + Polynomial(vec![coef]);
269 | }
270 | res
271 | }
272 | }
273 |
274 | impl FnOnce<(Polynomial,)> for Polynomial {
275 | type Output = Polynomial;
276 |
277 | extern "rust-call" fn call_once(self, args: (Polynomial,)) -> Self::Output {
278 | self.compose(args.0)
279 | }
280 | }
281 |
282 | impl FnMut<(Polynomial,)> for Polynomial {
283 | extern "rust-call" fn call_mut(&mut self, args: (Polynomial,)) -> Self::Output {
284 | self.compose(args.0)
285 | }
286 | }
287 |
288 | impl Fn<(Polynomial,)> for Polynomial {
289 | extern "rust-call" fn call(&self, args: (Polynomial,)) -> Self::Output {
290 | self.compose(args.0)
291 | }
292 | }
293 |
294 | impl FnOnce<(FieldElement,)> for Polynomial {
295 | type Output = FieldElement;
296 |
297 | extern "rust-call" fn call_once(self, args: (FieldElement,)) -> Self::Output {
298 | self.eval(args.0)
299 | }
300 | }
301 |
302 | impl FnMut<(FieldElement,)> for Polynomial {
303 | extern "rust-call" fn call_mut(&mut self, args: (FieldElement,)) -> Self::Output {
304 | self.eval(args.0)
305 | }
306 | }
307 |
308 | impl Fn<(FieldElement,)> for Polynomial {
309 | extern "rust-call" fn call(&self, args: (FieldElement,)) -> Self::Output {
310 | self.eval(args.0)
311 | }
312 | }
313 |
314 | impl FnOnce<(i128,)> for Polynomial {
315 | type Output = FieldElement;
316 |
317 | extern "rust-call" fn call_once(self, args: (i128,)) -> Self::Output {
318 | let fe: FieldElement = args.0.into();
319 | self.eval(fe)
320 | }
321 | }
322 |
323 | impl FnMut<(i128,)> for Polynomial {
324 | extern "rust-call" fn call_mut(&mut self, args: (i128,)) -> Self::Output {
325 | let fe: FieldElement = args.0.into();
326 | self.eval(fe)
327 | }
328 | }
329 |
330 | impl Fn<(i128,)> for Polynomial {
331 | extern "rust-call" fn call(&self, args: (i128,)) -> Self::Output {
332 | let fe: FieldElement = args.0.into();
333 | self.eval(fe)
334 | }
335 | }
336 |
337 | impl PartialEq for Polynomial {
338 | fn eq(&self, other: &usize) -> bool {
339 | let fe: FieldElement = (*other).into();
340 | let poly: Polynomial = fe.into();
341 | self == &poly
342 | }
343 | }
344 |
345 | impl PartialEq for Polynomial {
346 | fn eq(&self, other: &FieldElement) -> bool {
347 | let other_poly: Polynomial = (*other).into();
348 | self == &other_poly
349 | }
350 | }
351 |
352 | impl From for Polynomial {
353 | fn from(value: usize) -> Self {
354 | let fe: FieldElement = value.into();
355 | fe.into()
356 | }
357 | }
358 |
359 | impl From for Polynomial {
360 | fn from(value: FieldElement) -> Self {
361 | Polynomial::new(&[value])
362 | }
363 | }
364 |
365 | impl std::ops::Add for Polynomial {
366 | type Output = Polynomial;
367 |
368 | fn add(self, other: Self) -> Self::Output {
369 | Polynomial(Self::two_list_tuple_operation(
370 | &self.0,
371 | &other.0,
372 | |x, y| x + y,
373 | FieldElement::zero(),
374 | ))
375 | }
376 | }
377 |
378 | impl std::ops::Add for Polynomial {
379 | type Output = Polynomial;
380 |
381 | fn add(self, other: usize) -> Self::Output {
382 | let other_poly: Polynomial = other.into();
383 | self + other_poly
384 | }
385 | }
386 |
387 | impl std::ops::Add for Polynomial {
388 | type Output = Polynomial;
389 |
390 | fn add(self, other: FieldElement) -> Self::Output {
391 | let other_poly: Polynomial = other.into();
392 | self + other_poly
393 | }
394 | }
395 |
396 | impl std::ops::Sub for Polynomial {
397 | type Output = Polynomial;
398 |
399 | fn sub(self, other: Self) -> Self::Output {
400 | Polynomial(Self::two_list_tuple_operation(
401 | &self.0,
402 | &other.0,
403 | |x, y| x - y,
404 | FieldElement::zero(),
405 | ))
406 | }
407 | }
408 |
409 | impl std::ops::Sub for Polynomial {
410 | type Output = Polynomial;
411 |
412 | fn sub(self, other: usize) -> Self::Output {
413 | let other_fe: FieldElement = (-(other as i128)).into();
414 | let other_poly: Polynomial = other_fe.into();
415 | self + other_poly
416 | }
417 | }
418 |
419 | impl std::ops::Sub for Polynomial {
420 | type Output = Polynomial;
421 |
422 | fn sub(self, other: FieldElement) -> Self::Output {
423 | let other_poly: Polynomial = other.into();
424 |
425 | self - other_poly
426 | }
427 | }
428 |
429 | impl std::ops::Neg for Polynomial {
430 | type Output = Polynomial;
431 |
432 | fn neg(self) -> Self::Output {
433 | Polynomial(vec![]) - self
434 | }
435 | }
436 |
437 | impl std::ops::Mul for usize {
438 | type Output = Polynomial;
439 |
440 | fn mul(self, rhs: Polynomial) -> Self::Output {
441 | rhs * self
442 | }
443 | }
444 |
445 | impl std::ops::Mul for Polynomial {
446 | type Output = Polynomial;
447 |
448 | fn mul(self, other: Self) -> Self::Output {
449 | let mut res = [FieldElement::zero()].repeat((self.degree() + other.degree() + 1) as usize);
450 | for (i, c1) in self.0.clone().into_iter().enumerate() {
451 | if other.degree() > -1 {
452 | for (j, c2) in other.clone().0.into_iter().enumerate() {
453 | if let Some(value) = res.get_mut(i + j) {
454 | *value += c1 * c2;
455 | }
456 | }
457 | }
458 | }
459 | Polynomial(Self::trim_trailing_zeros(&res))
460 | }
461 | }
462 |
463 | impl std::ops::Mul for Polynomial {
464 | type Output = Polynomial;
465 |
466 | fn mul(self, other: usize) -> Self::Output {
467 | let other_poly: Polynomial = other.into();
468 | self * other_poly
469 | }
470 | }
471 |
472 | impl std::ops::Mul for Polynomial {
473 | type Output = Polynomial;
474 |
475 | fn mul(self, other: i128) -> Self::Output {
476 | let other_fe: FieldElement = other.into();
477 | let other_poly: Polynomial = other_fe.into();
478 | self * other_poly
479 | }
480 | }
481 |
482 | impl std::ops::Mul for Polynomial {
483 | type Output = Polynomial;
484 |
485 | fn mul(self, other: FieldElement) -> Self::Output {
486 | let other_poly: Polynomial = other.into();
487 | self * other_poly
488 | }
489 | }
490 |
491 | impl std::ops::Div for Polynomial {
492 | type Output = Polynomial;
493 |
494 | fn div(self, other: Self) -> Self::Output {
495 | let (div, rem) = self.qdiv(other);
496 |
497 | assert!(rem.0.is_empty(), "Polynomials are not divisible.");
498 | div
499 | }
500 | }
501 |
502 | impl std::ops::Div for Polynomial {
503 | type Output = Polynomial;
504 |
505 | fn div(self, other: usize) -> Self::Output {
506 | let other_poly: Polynomial = other.into();
507 | self / other_poly
508 | }
509 | }
510 |
511 | impl std::ops::Div for Polynomial {
512 | type Output = Polynomial;
513 |
514 | fn div(self, other: FieldElement) -> Self::Output {
515 | let other_poly: Polynomial = other.into();
516 | self / other_poly
517 | }
518 | }
519 |
520 | impl std::ops::Rem for Polynomial {
521 | type Output = Polynomial;
522 |
523 | fn rem(self, other: Self) -> Self::Output {
524 | let (_, remainder) = self.qdiv(other);
525 | remainder
526 | }
527 | }
528 |
529 | #[cfg(test)]
530 | mod tests {
531 | use std::collections::HashSet;
532 |
533 | use super::{x, Polynomial};
534 | use crate::{field::FieldElement, parts};
535 | use itertools::Itertools;
536 | use rand::Rng;
537 |
538 | /// Returns a random polynomial of a prescribed degree which is not the zero polynomial.
539 | fn generate_random_polynomial(degree: usize) -> Polynomial {
540 | let leading = FieldElement::random_element(&[FieldElement::zero()]);
541 | let mut elems = (0..degree)
542 | .into_iter()
543 | .map(|_| FieldElement::random_element(&[]))
544 | .collect_vec();
545 | elems.push(leading);
546 | Polynomial(elems)
547 | }
548 |
549 | #[test]
550 | fn test_generate_polynomial() {
551 | let generated_poly = generate_random_polynomial(5);
552 | assert_eq!(5, generated_poly.degree())
553 | }
554 |
555 | #[test]
556 | fn test_poly_mul() {
557 | let result = (x() + 1) * (x() + 1);
558 | let expected = x().pow(2) + x() * 2usize + 1;
559 | assert_eq!(result, expected)
560 | }
561 |
562 | #[test]
563 | fn test_poly_mul_empty() {
564 | let empty_poly = Polynomial::new(&[]);
565 | let result = empty_poly.clone() * FieldElement::new(3) * (x() + 1)
566 | + empty_poly.clone() * Polynomial::prod(&[1.into(), 2.into(), 100.into()]);
567 | let expected = empty_poly;
568 | assert_eq!(result, expected)
569 | }
570 |
571 | #[test]
572 | fn test_div() {
573 | let p = x().pow(2) - FieldElement::one();
574 | assert_eq!(p / (x() - FieldElement::one()), x() + FieldElement::one())
575 | }
576 |
577 | #[test]
578 | fn test_modulo() {
579 | let p: Polynomial = x().pow(9) - (x() * 5usize) + 4;
580 | assert_eq!(p.modulo(x().pow(2) + 1), x() * (-4i128) + 4)
581 | }
582 |
583 | #[test]
584 | fn test_prod() {
585 | let g = FieldElement::generator().pow((FieldElement::k_modulus() - 1) / 1024);
586 | let polys = (0..1024).into_iter().map(|i| x() - g.pow(i)).collect_vec();
587 | assert_eq!(
588 | x().pow(1024) - FieldElement::one(),
589 | Polynomial::prod(&polys)
590 | )
591 | }
592 |
593 | #[test]
594 | fn test_call_compose() {
595 | let p = x().pow(2) + x();
596 | assert_eq!(p(x() + 1), x().pow(2) + x() * 3usize + 2)
597 | }
598 |
599 | #[test]
600 | fn test_call_eval() {
601 | let p = x().pow(2) + x();
602 | assert_eq!(p(5), 30)
603 | }
604 |
605 | #[test]
606 | fn test_div_rand_poly() {
607 | let iterations = 20;
608 | let mut rng = rand::thread_rng();
609 | for _ in 0..iterations {
610 | let degree_a = rng.gen_range(0..50);
611 | let degree_b = rng.gen_range(0..50);
612 | let poly_a = generate_random_polynomial(degree_a);
613 | let poly_b = generate_random_polynomial(degree_b);
614 | let (q, r) = poly_a.qdiv(poly_b.clone());
615 | let d = r.clone() + q * poly_b.clone();
616 | assert!(r.degree() < poly_b.degree());
617 | assert_eq!(d, poly_a);
618 | }
619 | }
620 |
621 | #[test]
622 | fn test_poly_interpolation() {
623 | let mut rng = rand::thread_rng();
624 | for _ in 0..10 {
625 | let degree = rng.gen_range(0..100);
626 | let p = generate_random_polynomial(degree);
627 | let mut x_values_set: HashSet<_> = HashSet::new();
628 | // Evaluate it on a number of points that is at least its degree.
629 | while x_values_set.len() < degree + 1 {
630 | x_values_set.insert(FieldElement::random_element(&[]));
631 | }
632 | let x_values: Vec = x_values_set.into_iter().collect_vec();
633 | let y_values = x_values
634 | .clone()
635 | .into_iter()
636 | .map(|x| p.eval(x))
637 | .collect_vec();
638 | // Obtain a polynomial from the evaluation.
639 | let interpolated_p = Polynomial::interpolate(&x_values, &y_values);
640 | assert_eq!(p, interpolated_p)
641 | }
642 | }
643 |
644 | #[test]
645 | fn test_compose() {
646 | let mut rng = rand::thread_rng();
647 | for _ in 0..10 {
648 | let outer_poly = generate_random_polynomial(rng.gen_range(0..1024));
649 | let inner_poly = generate_random_polynomial(rng.gen_range(0..16));
650 | // Validate th evaluation of the composition poly outer_poly(inner_poly) on a random point.
651 | let point = FieldElement::random_element(&[]);
652 | let result = outer_poly.clone()(inner_poly.clone()).eval(point);
653 | let expected = outer_poly.eval(inner_poly.eval(point));
654 | assert_eq!(result, expected);
655 | }
656 | }
657 |
658 | #[test]
659 | fn test_polynomial_pow() {
660 | let (_, g, _, _, _, _, f, _, _, _) = parts::part1();
661 | let numer_1 = f(x() * g.pow(2));
662 | let numer_2 = f(x() * g).pow(2)
663 | * FieldElement::new((-1 + FieldElement::k_modulus() as i128) as usize);
664 | let numer_3 =
665 | f.pow(2) * FieldElement::new((-1 + FieldElement::k_modulus() as i128) as usize);
666 | let numer = numer_1 + numer_2 + numer_3;
667 | assert_eq!(FieldElement::new(0), numer(g.pow(1020)));
668 | assert_eq!(FieldElement::new(230576507), numer(g.pow(1021)));
669 | }
670 |
671 | #[test]
672 | fn test_compose_session2() {
673 | let q = 2 * x().pow(2) + 1;
674 | let r = x() - 3;
675 | let expected = (2 * x().pow(2)) - 12 * x() + 19;
676 |
677 | assert_eq!(expected, q(r));
678 | }
679 | }
680 |
--------------------------------------------------------------------------------