diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 0156177cc..41080eb25 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -30,13 +30,13 @@ jobs: - name: Run cargo check run: cargo check - - name: Run cargo check cli and stark instruments + - name: Run cargo check and stark instruments run: | - cargo check --features cli,instruments + cargo check --features instruments - name: Run cargo check cli, stark instruments and parallel run: | - cargo check --features cli,instruments,parallel + cargo check --features instruments,parallel - name: Run cargo check for math with no-std run: cargo check --package lambdaworks-math --no-default-features @@ -104,15 +104,6 @@ jobs: - name: Set up cargo cache uses: Swatinem/rust-cache@v2 - - name: Python3 build - uses: actions/setup-python@v4 - with: - python-version: "3.9" - cache: "pip" - - - name: Install cairo-lang toolchain and dependencies - run: pip install -r provers/cairo/requirements.txt - - name: Install testing tools uses: taiki-e/install-action@v2 with: @@ -171,12 +162,6 @@ jobs: - name: Install wasm-pack tools for testing run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - name: Run wasm-pack tests in firefox - run: cd provers/cairo && wasm-pack test --release --firefox --headless -- --features wasm - - - name: Run wasm-pack tests in chrome - run: cd provers/cairo && wasm-pack test --release --chrome --headless -- --features wasm - test_macos: name: Test (macOS, Apple sillicon) runs-on: macos-latest @@ -196,18 +181,6 @@ jobs: toolchain: stable components: clippy - - name: Python3 build - uses: actions/setup-python@v4 - with: - python-version: "3.9" - cache: "pip" - - - name: Install cairo-lang toolchain and dependencies - env: - CFLAGS: "-I/opt/homebrew/opt/gmp/include" - LDFLAGS: "-L/opt/homebrew/opt/gmp/lib" - run: pip install -r provers/cairo/requirements.txt - - name: Run clippy run: make clippy-metal diff --git a/.github/workflows/criterion_benchs.yml b/.github/workflows/criterion_benchs.yml index a4b9a69ee..5586f5a76 100644 --- a/.github/workflows/criterion_benchs.yml +++ b/.github/workflows/criterion_benchs.yml @@ -51,16 +51,7 @@ jobs: run: | brew install gcc brew install gmp - - name: Python3 build - uses: actions/setup-python@v4 - with: - python-version: "3.9" - cache: "pip" - - name: Install cairo-lang toolchain and dependencies - env: - CFLAGS: "-I/opt/homebrew/opt/gmp/include" - LDFLAGS: "-L/opt/homebrew/opt/gmp/lib" - run: pip install -r provers/cairo/requirements.txt + - name: Run benchmark run: | cargo bench -F metal --no-fail-fast --bench "criterion_metal" \ diff --git a/Cargo.toml b/Cargo.toml index 38c9a23e0..52c7e1edf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/cairo", "provers/groth16", "provers/groth16/arkworks-adapter", "provers/groth16/circom-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "provers/winterfell_adapter", "examples/shamir_secret_sharing","examples/pinocchio", "examples/prove-verify-circom", "provers/cairo/ffi", "examples/baby-snark"] +members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/groth16", "provers/groth16/arkworks-adapter", "provers/groth16/circom-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "provers/winterfell_adapter", "examples/shamir_secret_sharing","examples/pinocchio", "examples/prove-verify-circom", "examples/baby-snark"] exclude = ["ensure-no_std"] resolver = "2" @@ -16,7 +16,6 @@ lambdaworks-crypto = { path = "./crypto", version = "0.10.0", default-features = lambdaworks-gpu = { path = "./gpu", version = "0.10.0" } lambdaworks-math = { path = "./math", version = "0.10.0", default-features = false } stark-platinum-prover = { path = "./provers/stark" } -cairo-platinum-prover = { path = "./provers/cairo" } lambdaworks-winterfell-adapter = { path = "./provers/winterfell_adapter"} lambdaworks-groth16 = { path = "./provers/groth16" } lambdaworks-circom-adapter = { path = "./provers/groth16/circom-adapter" } diff --git a/Makefile b/Makefile index 627feec6f..1369132d5 100644 --- a/Makefile +++ b/Makefile @@ -4,26 +4,12 @@ FUZZ_DIR = fuzz/no_gpu_fuzz ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -CAIRO0_PROGRAMS_DIR=provers/cairo/cairo_programs/cairo0 -CAIRO0_PROGRAMS:=$(wildcard $(CAIRO0_PROGRAMS_DIR)/*.cairo) -COMPILED_CAIRO0_PROGRAMS:=$(patsubst $(CAIRO0_PROGRAMS_DIR)/%.cairo, $(CAIRO0_PROGRAMS_DIR)/%.json, $(CAIRO0_PROGRAMS)) - -# Rule to compile Cairo programs for testing purposes. -# If the `cairo-lang` toolchain is installed, programs will be compiled with it. -# Otherwise, the cairo_compile docker image will be used -# When using the docker version, be sure to build the image using `make docker_build_cairo_compiler`. -$(CAIRO0_PROGRAMS_DIR)/%.json: $(CAIRO0_PROGRAMS_DIR)/%.cairo - @echo "Compiling Cairo program..." - @cairo-compile --cairo_path="$(CAIRO0_PROGRAMS_DIR)" $< --output $@ 2> /dev/null --proof_mode || \ - docker run --rm -v $(ROOT_DIR)/$(CAIRO0_PROGRAMS_DIR):/pwd/$(CAIRO0_PROGRAMS_DIR) cairo --proof_mode /pwd/$< > $@ - -test: $(COMPILED_CAIRO0_PROGRAMS) +test: cargo test clippy: cargo clippy --workspace --all-targets -- -D warnings cargo clippy --workspace --all-targets --features wasm -- -D warnings - cargo clippy --workspace --all-targets --features cli -- -D warnings cargo clippy --workspace --all-targets --features parallel -- -D warnings cargo clippy --tests @@ -47,7 +33,7 @@ benchmark: flamegraph_stark: CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --root --bench stark_benchmarks -- --bench -coverage: $(COMPILED_CAIRO0_PROGRAMS) +coverage: cargo llvm-cov nextest --lcov --output-path lcov.info METAL_DIR = math/src/gpu/metal @@ -57,7 +43,7 @@ build-metal: clippy-metal: cargo clippy --workspace --all-targets -F metal -- -D warnings -test-metal: $(COMPILED_CAIRO0_PROGRAMS) +test-metal: cargo test -F metal CUDA_DIR = math/src/gpu/cuda/shaders @@ -91,9 +77,3 @@ run-metal-fuzzer: run-cuda-fuzzer: cd fuzz/cuda_fuzz cargo hfuzz run $(CUDAFUZZER) - -build_wasm: - cd provers/cairo && wasm-pack build --release --target=web -- --features wasm - -test_wasm_with_firefox: - cd provers/cairo && wasm-pack test --release --firefox --headless -- --features wasm diff --git a/README.md b/README.md index 7ec04fcff..f95c93f66 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,20 @@ This library provides efficient implementation of cryptographic primitives used +## Examples - mini apps + +Below is a list of examples to understand lambdaworks and learn what you can build with the tools provided. + +- [Merkle Tree CLI](./examples/merkle-tree-cli/) +- [Proving Miden](./examples/prove-miden/) +- [Shamir's secret sharing](./examples/shamir_secret_sharing/) +- [BabySNARK](./examples/baby-snark/) +- [Pinocchio](./examples/pinocchio/) +- [Using Circom with lambdaworks's Groth16](./provers/groth16/circom-adapter/src/README.md) + +- You can use Circom to generate circuits and use lambdaworks's capabilities to prove the execution with [Groth16](./provers/groth16/README.md). +- You can use the [Stark prover](./provers/stark/src/) to define an algebraic intermediate representation (AIR) and prove the execution of a program + ## Why we built lambdaworks Zero-Knowledge and Validity Proofs have gained a lot of attention over the last few years. We strongly believe in this potential and that is why we decided to start working in this challenging ecosystem, where math, cryptography and distributed systems meet. The main barrier in the beginning was not the cryptography or math but the lack of good libraries which are performant and developer friendly. There are some exceptions, though, like gnark or halo2. Some have nice APIs and are easy to work with, but they are not written in Rust, and some are written in Rust but have poor programming and engineering practices. Most of them don't have support for CUDA, Metal and WebGPU or distributed FFT calculation using schedulers like Dask. @@ -29,7 +43,6 @@ So, we decided to build our library, focusing on performance, with clear documen - [Crypto primitives](https://github.com/lambdaclass/lambdaworks/tree/main/crypto) - [STARK Prover](https://github.com/lambdaclass/lambdaworks/tree/main/provers/stark) - [Plonk Prover](https://github.com/lambdaclass/lambdaworks/tree/main/provers/plonk) -- [Cairo Prover](https://github.com/lambdaclass/lambdaworks/tree/main/provers/cairo) - [Groth 16](https://github.com/lambdaclass/lambdaworks/tree/main/provers/groth16) ### Crypto @@ -42,14 +55,6 @@ Most of math and crypto crates supports no-std without allocation with `no-defau Both Math and Crypto support wasm with target `wasm32-unknown-unknown`. To see an example of how to use this to deploy a verifier in a browser, check the Cairo Prover wasm-pack verifier. -## Examples - mini apps - -- [Merkle Tree CLI](https://github.com/lambdaclass/lambdaworks/tree/main/examples/merkle-tree-cli) -- [Proving Miden](https://github.com/lambdaclass/lambdaworks/tree/main/examples/prove-miden) -- [Shamir's secret sharing](https://github.com/lambdaclass/lambdaworks/tree/main/examples/shamir_secret_sharing) -- [BabySNARK](https://github.com/lambdaclass/lambdaworks/tree/main/examples/baby-snark) -- [Pinocchio](https://github.com/lambdaclass/lambdaworks/tree/main/examples/pinocchio) - ## Exercises and Challenges - [lambdaworks exercises and challenges](https://github.com/lambdaclass/lambdaworks_exercises/tree/main) @@ -83,9 +88,10 @@ List of symbols: | Mersenne 31 | :heavy_check_mark: | :x: | :x: | :x: | :x: | | Baby Bear | :heavy_check_mark: | :x: | :x: | :x: | :x: | | MiniGoldilocks | :heavy_check_mark: | :x: | :x: | :heavy_check_mark: | :x: | +| Binary fields | :x: | :x: | :x: | :x: | :x: | | **ZK friendly Hash function** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | -| Poseidon | πŸ—οΈ | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | -| Pedersen | πŸ—οΈ | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | +| Poseidon | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | +| Pedersen | πŸ—οΈ | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | | Rescue Prime XLIX | :x: | :x: | :x: | :x: | :x: | | **Elliptic Curves** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | BLS12-381 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | @@ -99,24 +105,16 @@ List of symbols: | secq256r1 | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :x: | :x: | | **STARKs** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | STARK Prover | :heavy_check_mark: | :x: | :x: | :x: | :x: | -| CAIRO Prover | πŸ—οΈ | :x: | :x: | :x: | :x: | +| Circle STARKs | :x: | :x: | :x: | :x: | :x: | | **SNARKs** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | Groth16 | :heavy_check_mark: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | | Plonk | πŸ—οΈ | :heavy_check_mark: | βœ”οΈ | :heavy_check_mark: | :x: | -| Spartan | :x: | :heavy_check_mark: | :x: | :x: | :x: | -| Marlin | :x: | :heavy_check_mark: | :x: | :x: | :x: | | GKR | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | | **Polynomial Commitment Schemes** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | KZG10 | :heavy_check_mark: | βœ”οΈ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | FRI | πŸ—οΈ | :x: | :x: | :heavy_check_mark: | :x: | -| IPA | πŸ—οΈ | βœ”οΈ | :heavy_check_mark: | :x: | :x: | -| Brakedown | :x: | :x: | :x: | :x: | :x: | -| Basefold | :x: | :x: | :x: | :x: | :x: | -| **Folding Schemes** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | -| Nova | :x: | :heavy_check_mark: | :x: | :x: | :x: | -| Supernova | :x: | :x: | :x: | :x: | :x: | -| Protostar | :x: | :x: | :x: | :x: | :x: | -| Protogalaxy | :x: | :heavy_check_mark: | :x: | :x: | :x: | +| Binius | :x: | :x: | :x: | :x: | :x: | +| Circle FRI | :x: | :x: | :x: | :x: | :x: | Additionally, provers are compatible with the following frontends and VMs: @@ -129,7 +127,6 @@ Additionally, provers are compatible with the following frontends and VMs: | Plonk | Noir | :x: | | Stark | Winterfell | :heavy_check_mark: | | Stark | Miden | :heavy_check_mark: | -| Stark | Cairo | :heavy_check_mark: | This can be used in a multi prover setting for extra security, or as a standalone to be used with Rust. diff --git a/bootcamp/0_groth_16.jpg b/bootcamp/0_groth_16.jpg deleted file mode 100644 index 93e054488..000000000 Binary files a/bootcamp/0_groth_16.jpg and /dev/null differ diff --git a/bootcamp/0_snarks_starks.jpg b/bootcamp/0_snarks_starks.jpg deleted file mode 100644 index ea6beef07..000000000 Binary files a/bootcamp/0_snarks_starks.jpg and /dev/null differ diff --git a/bootcamp/0_starks_constraints.jpg b/bootcamp/0_starks_constraints.jpg deleted file mode 100644 index edba953fb..000000000 Binary files a/bootcamp/0_starks_constraints.jpg and /dev/null differ diff --git a/bootcamp/0_starks_general.jpg b/bootcamp/0_starks_general.jpg deleted file mode 100644 index 51d20acfb..000000000 Binary files a/bootcamp/0_starks_general.jpg and /dev/null differ diff --git a/bootcamp/0_starks_proof.jpg b/bootcamp/0_starks_proof.jpg deleted file mode 100644 index 2a75e1da2..000000000 Binary files a/bootcamp/0_starks_proof.jpg and /dev/null differ diff --git a/bootcamp/README.md b/bootcamp/README.md deleted file mode 100644 index 0f49e9469..000000000 --- a/bootcamp/README.md +++ /dev/null @@ -1,247 +0,0 @@ -# Lambda's Sparkling Water Bootcamp - Repo for challenges and learning path - -Public repository for exercises, challenges and all the needs of the Sparkling Water Bootcamp. - -## Week 1 - Forging your tools: Finite Fields - -This first week will be focused on the development of one of the building blocks of Cryptography: Finite Fields. - -### Recommended material: - -- [An introduction to mathematical cryptography](https://books.google.com.ar/books/about/An_Introduction_to_Mathematical_Cryptogr.html?id=BHuTQgAACAAJ&source=kp_book_description&redir_esc=y) - Chapter 1. -- [Finite Fields](https://www.youtube.com/watch?v=MAhmV_omOwA&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=8) -- [Constructing finite fields](https://www.youtube.com/watch?v=JPiXFn9WA5Y&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=6) -- [Cyclic groups](https://www.youtube.com/watch?v=UIhhs38IAGM&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=3) -- [Summary on Montgomery arithmetic](https://eprint.iacr.org/2017/1057.pdf) -- [Mersenne primes](https://eprint.iacr.org/2023/824.pdf) - -### Challenges: - -- [Implement Montgomery backend for 32 bit fields](https://github.com/lambdaclass/lambdaworks/issues/538). -- [Implement efficient Mersenne prime backend](https://github.com/lambdaclass/lambdaworks/issues/540). -- [Implement efficient backend for pseudo-Mersenne primes](https://github.com/lambdaclass/lambdaworks/issues/393). -- Compare specific field implementations with ordinary Montgomery arithmetic. - -### Cryptography content: - -- [Serious Cryptography](https://books.google.com.ar/books/about/Serious_Cryptography.html?id=1D-QEAAAQBAJ&source=kp_book_description&redir_esc=y), Chapters 9 & 10. - -### Exercises -- Implement naΓ―ve version of RSA. -- $7$ is a generator of the multiplicative group of $Z_p^\star$, where $p = 2^{64} - 2^{32} +1$. Find the generators for the $2^{32}$ roots of unity. Find generators for subgroups of order $2^{16} + 1$ and $257$. -- Define in your own words what is a group, a subgroup, a ring and a field. -- What are the applications of the Chinese Remainder Theorem in Cryptography? -- Find all the subgroups of the multiplicative group of $Z_{29}^\star$ - -## Supplementary Material -- [Polynomial Secret Sharing](https://decentralizedthoughts.github.io/2020-07-17-polynomial-secret-sharing-and-the-lagrange-basis/) -- [Polynomials over a Field](https://decentralizedthoughts.github.io/2020-07-17-the-marvels-of-polynomials-over-a-field/) -- [Fourier Transform](https://www.youtube.com/watch?v=spUNpyF58BY) -- [Fast Fourier Transform](https://www.youtube.com/watch?v=h7apO7q16V0) - -## Week 2 - Enter Elliptic Curves - -During the second week we'll continue with Finite Fields and begin with Elliptic Curves and dive deeper into Rust - -### Recommended material - -- [Moonmath Manual](https://leastauthority.com/community-matters/moonmath-manual/) - Chapter 5, until 5.3 -- [Programming Bitcoin](https://books.google.fr/books/about/Programming_Bitcoin.html?id=O2aHDwAAQBAJ&source=kp_book_description&redir_esc=y) - Chapters 2 & 3. -- [Introduction to Mathematical Cryptography](https://books.google.com.ar/books/about/An_Introduction_to_Mathematical_Cryptogr.html?id=BHuTQgAACAAJ&source=kp_book_description&redir_esc=y) - Chapter 5 until 5.5 -- [Serious Cryptography](https://books.google.com.ar/books/about/Serious_Cryptography.html?id=1D-QEAAAQBAJ&source=kp_book_description&redir_esc=y) - Chapters 11 & 12. -- [Pairings for Beginners](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) - Chapters 1 & 2 - -### Exercises - -- Define an elliptic curve element type. -- Implement the basic operations: addition and doubling. -- Implement scalar multiplication. -- Check that the point belongs to the correct subgroup. -- The BLS12-381 elliptic curve is given by the equation $y^2 = x^3 + 4$ and defined over $\mathbb{F}_p$ with p = 0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab. The group generator is given by the point p1 = (0x04, 0x0a989badd40d6212b33cffc3f3763e9bc760f988c9926b26da9dd85e928483446346b8ed00e1de5d5ea93e354abe706c) and the cofactor is $h_1 = 0x396c8c005555e1568c00aaab0000aaab$. Find the generator $g$ of the subgroup of order -r = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001. -- Implement a naΓ―ve version of the Diffie - Hellman protocol -- Implement point compression and decompression to store elliptic curve points - -### Challenges - -- Special CTF challenge (will be revealed later) -- [Implement BN254](https://github.com/lambdaclass/lambdaworks/issues/548) -- Implement Secp256k1 -- Implement Ed25519 - -### Rust Workshop - -- [Aguante Rust](https://youtu.be/nYpMbjzb1t8?si=HNanyXYWcu1xDjG5) - -## Week 3: Polynomials - -### Recommended material - -- [Polynomials](https://www.youtube.com/watch?v=HiaJa3yhHTU&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=6) -- [Lagrange interpolation](https://www.youtube.com/watch?v=REnFOKo9gXs&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=10) -- [Lagrange interpolation and secret sharing](https://www.youtube.com/watch?v=3g4wZnhl4m8&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=3) -- [Moonmath](https://leastauthority.com/community-matters/moonmath-manual/) - Chapter 3.4 -- [Convolution polynomial rings - Introduction to Mathematical Cryptography](https://books.google.com.ar/books/about/An_Introduction_to_Mathematical_Cryptogr.html?id=BHuTQgAACAAJ&source=kp_book_description&redir_esc=y) - Chapter 6.9 - -### Supplementary - -- [Roots of unity and polynomials](https://www.youtube.com/watch?v=3KK5RuAgOpA&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=2) -- [Fast Fourier Transform](https://www.youtube.com/watch?v=toj_IoCQE-4) -- [FFT walkthrough](https://www.youtube.com/watch?v=Ty0JcR6Dvis) - -### Exercises - -- Define a polynomial type. -- Implement basic operations, such as addition, multiplication and evaluation. -- Implement Lagrange polynomial interpolation. -- Implement basic version of Shamir's secret sharing. - -### Issue - -- [Implement Stockham FFT](http://wwwa.pikara.ne.jp/okojisan/otfft-en/stockham1.html) - -## Week 4: STARKs - -### Recommended material - -- [STARKs by Sparkling Water Bootcamp](https://www.youtube.com/watch?v=cDzTm3clrEo) -- [Lambdaworks Docs](https://github.com/lambdaclass/lambdaworks/tree/main/docs/src/starks) -- [Stark 101](https://github.com/starkware-industries/stark101) -- [Constraints](https://blog.lambdaclass.com/periodic-constraints-and-recursion-in-zk-starks/) -- [Stark 101 - rs](https://github.com/lambdaclass/stark101-rs/) -- [Anatomy of a STARK](https://aszepieniec.github.io/stark-anatomy/) -- [BrainSTARK](https://aszepieniec.github.io/stark-brainfuck/) -- [A summary on FRI low degree testing](https://eprint.iacr.org/2022/1216) -- [STARKs by Risc0](https://dev.risczero.com/reference-docs/about-starks) - -### Exercises - -- Complete STARK-101 - -## Week 5: Symmetric encryption - -### Recommended material - -- [One time pad - Dan Boneh](https://www.youtube.com/watch?v=pQkyFJp2eUg&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=6) -- [Stream ciphers and pseudorandom generators - Dan Boneh](https://www.youtube.com/watch?v=ZSjTMSvp-eI&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=7) -- [Attacks - Dan Boneh](https://www.youtube.com/watch?v=Qm8fycVt5v8&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=8) -- [Semantic security - Dan Boneh](https://www.youtube.com/watch?v=6LFyXO58F4A&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=11) -- [Block ciphers - Dan Boneh](https://www.youtube.com/watch?v=dzoqxqfpZB4&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=35) -- [Serious Cryptography](https://books.google.com.ar/books/about/Serious_Cryptography.html?id=1D-QEAAAQBAJ&source=kp_book_description&redir_esc=y) - Chapters 3 - 5. - -### Supplementary material - -- [AES - NIST](https://nvlpubs.nist.gov/nistpubs/fips/nist.fips.197.pdf) - -### Exercises - -- Implement AES round function - -### Side project - Multilinear polynomials - -- [Proofs, Args and ZK](https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf) - -### Mandatory task - -- Choose a project: STARKs, Sumcheck protocol or Groth16 (or propose a new project) - -### Additional resources for each project - -- STARKs: see week 4. -- [Groth16](https://eprint.iacr.org/2016/260.pdf) -- [DIZK - Groth 16](https://eprint.iacr.org/2018/691.pdf) -- [Multilinear polynomials and sumcheck protocol](https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf) - -#### Challenges - -- Implement a multilinear polynomial type with all the basic operations. - -## Week 6: Interactive proofs and SNARKs - -- [Moonmath](https://leastauthority.com/community-matters/moonmath-manual/) Chapters 6 - 8. -- [Proofs, Arguments and Zero Knowledge](https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf) Chapters 1 - 5. -- [Overview of modern SNARK constructions](https://www.youtube.com/watch?v=bGEXYpt3sj0) -- [Pinocchio protocol overview](https://www.zeroknowledgeblog.com/index.php/zk-snarks) -- [Pinocchio implementation](https://github.com/lambdaclass/pinocchio_lambda_vm) -- [SNARKs and STARKs](https://zkhack.dev/whiteboard/module-four/) - -### Additional material on some proof systems - -- [EthSTARK](https://github.com/starkware-libs/ethSTARK/tree/master) -- [EthSTARK - paper](https://eprint.iacr.org/2021/582) -- [STARK paper](https://eprint.iacr.org/2018/046.pdf) -- [DEEP FRI](https://eprint.iacr.org/2019/336) -- [Proximity gaps](https://eprint.iacr.org/2020/654) -- [STARKs by Eli Ben-Sasson I](https://www.youtube.com/watch?v=9VuZvdxFZQo) -- [STARKs by Eli Ben-Sasson II](https://www.youtube.com/watch?v=L7tZeO8ihcQ) - -## Week 7: Plonk - -- [Plonk](https://eprint.iacr.org/2019/953) -- [Custom gates](https://zkhack.dev/whiteboard/module-five/) -- [Plonk by hand](https://research.metastate.dev/plonk-by-hand-part-1/) -- [Plonk docs in Lambdaworks](https://github.com/lambdaclass/lambdaworks/tree/main/docs/src/plonk) - -## Week 8: Lookup arguments - -- [Plookup](https://eprint.iacr.org/2020/315.pdf) -- [LogUp and GKR](https://eprint.iacr.org/2023/1284.pdf) -- [Neptune - Permutation Argument](https://neptune.cash/learn/tvm-cross-table-args/) -- [Randomized AIR with preprocessing](https://hackmd.io/@aztec-network/plonk-arithmetiization-air) -- [PlonkUp](https://eprint.iacr.org/2022/086.pdf) -- [Lookups by Ingonyama](https://medium.com/@ingonyama/a-brief-history-of-lookup-arguments-a4eeeeca2749) -- [LogUp](https://eprint.iacr.org/2022/1530.pdf) -- [Lookups - Halo2](https://zcash.github.io/halo2/design/proving-system/lookup.html) - -## Week 9: Signatures - -- [BLS signatures](https://www.ietf.org/archive/id/draft-irtf-cfrg-bls-signature-05.html#name-introduction-2) -- [Real World Cryptography](https://books.google.com.ar/books/about/Real_World_Cryptography.html?id=Qd5CEAAAQBAJ&source=kp_book_description&redir_esc=y) Chapter 7 -- [ECDSA](https://www.rfc-editor.org/rfc/rfc6605.txt) -- [RSA Signature](https://www.ietf.org/rfc/rfc8017.html#section-5.2) - -## Week 10: Folding schemes - -- [Nova by Justin Drake](https://zkhack.dev/whiteboard/module-fourteen/) -- [Nova](https://eprint.iacr.org/2021/370) -- [SuperNova](https://eprint.iacr.org/2022/1758) -- [ProtoStar](https://eprint.iacr.org/2023/620) -- [ProtoGalaxy](https://eprint.iacr.org/2023/1106) - -## Projects - -- Implement IPA commitment scheme -- Implement Jacobian coordinates for Elliptic Curves -- Benchmark elliptic curve operations -- Add improvements to fixed base scalar multiplication in Elliptic Curves -- Add BN254 elliptic curve -- Implement Pasta curves -- Implement Lookup arguments for Plonk (Plookup) -- Sumcheck protocol -- Benchmark and optimize multilinear polynomial operations -- Import circuits from gnark or circom to use with Groth16 backend - -### Links to repos with solutions to the exercises -- [NaΓ―ve ECC](https://github.com/saitunc/naive_ecc) -- [Crypto](https://github.com/irfanbozkurt/crypto) -- [NaΓ―ve RSA](https://github.com/WiseMrMusa/rsa-naive) -- [NaΓ―ve RSA](https://github.com/Elvis339/naive_rsa) -- [Exercises from weeks 1 & 2](https://github.com/ArpitxGit/sparkling_water_bootcamp/tree/main) -- [Programming bitcoin EC](https://github.com/Elvis339/rbtc) -- [Shamir secret sharing](https://github.com/cliraa/shamir_secret_sharing) -- [Several exercises](https://github.com/ArpitxGit/sparkling_water_bootcamp/tree/main) - -### Intended Roadmap - -- Finite Fields -- Elliptic Curves -- Polynomials -- Extension fields -- Pairings -- Public key encryption -- Symmetric encryption -- Hash functions -- Signatures -- Authenticated encryption -- SNARKs -- STARKs diff --git a/bootcamp/WhiteboardDiscussion.png b/bootcamp/WhiteboardDiscussion.png deleted file mode 100644 index 3a912e992..000000000 Binary files a/bootcamp/WhiteboardDiscussion.png and /dev/null differ diff --git a/bootcamp/WhiteboardPolynomials.png b/bootcamp/WhiteboardPolynomials.png deleted file mode 100644 index 8f1916ff6..000000000 Binary files a/bootcamp/WhiteboardPolynomials.png and /dev/null differ diff --git a/bootcamp/WhiteboardRSA.png b/bootcamp/WhiteboardRSA.png deleted file mode 100644 index b60c48f19..000000000 Binary files a/bootcamp/WhiteboardRSA.png and /dev/null differ diff --git a/bootcamp/learning_resources.md b/bootcamp/learning_resources.md deleted file mode 100644 index 6dcc37302..000000000 --- a/bootcamp/learning_resources.md +++ /dev/null @@ -1,94 +0,0 @@ -# Roadmap - -## 1. Fundamentals of Cryptography and Mathematics - -### Key Concepts: -- What is cryptography. - - [Cryptography I - Dan Boneh: Videos 1, 2 and 3.](https://youtube.com/playlist?list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&si=M8qItPK_HUy3WR7b) -- Symmetric ciphers: the one time pad and stream ciphers. - - [Cryptography I - Dan Boneh: Videos 6, 7, 8 and 9.](https://www.youtube.com/watch?v=pQkyFJp2eUg&list=PL58C6Q25sEEHXvACYxiav_lC2DqSlC7Og&index=7) -- Exclusive or. - - [Crypto101: Chapter 5](https://www.crypto101.io/) -- Block ciphers. - - [Crypto101: Chapter 6](https://www.crypto101.io/) -- Number Theory: Modular arithmetic and prime numbers - - [An Introduction to Mathematical Cryptography: Chapter 1](https://link.springer.com/book/10.1007/978-0-387-77993-5) -- Public key cryptography: Discrete logarithms and Diffie-Hellman. - - [An Introduction to Mathematical Cryptography: Chapters from 2.1 to 2.4](https://link.springer.com/book/10.1007/978-0-387-77993-5) -- Abstract Algebra: Group Theory. - - [An Introduction to Mathematical Cryptography: Chapter 2.5](https://link.springer.com/book/10.1007/978-0-387-77993-5) -- Abstract Algebra: Rings and finite fields. - - [An Introduction to Mathematical Cryptography: Chapter 2.10](https://link.springer.com/book/10.1007/978-0-387-77993-5) -- Finite Field Theory: Operations and applications in cryptography. -- RSA. - - [How RSA Works](https://www.youtube.com/watch?v=qph77bTKJTM&t=1060s) -- Basic Cryptography: hash functions, and digital signatures. - - [What are Digital Signatures?](https://www.youtube.com/watch?v=s22eJ1eVLTU) - - -## 2. Theory and Application of Elliptic Curves - -### Key Concepts: -- Elliptic Curves over Finite Fields: Definition and operations. - - [Elliptic Curves - Computerphile](https://www.youtube.com/watch?v=NF1pwjL9-DE) -- Elliptic Curve Cryptography (ECC): Applications and advantages. -- Points and Operations on Elliptic Curves: Point addition and scalar multiplication. -- Pairing - - [Pairing for Beginners](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) Chapter 1 & 2 - - -## 3. Introduction to Zero-Knowledge Proofs - -### Key Concepts: -- Definition and Properties: Completeness, soundness, and zero-knowledge. - - [Computer Scientist Explains One Concept in 5 Levels of Difficulty](https://www.youtube.com/watch?v=fOGdb1CTu5c) - - -## 4. SNARKs (Succinct Non-Interactive Arguments of Knowledge) - -### Key Concepts: -- Introduction to SNARKs: Concepts and uses. - - [What is a zk-SNARK?](https://www.youtube.com/watch?v=gcKCW7CNu_M) -- Components of SNARKs: Arithmetization, constraint systems, and quadratic arithmetic programs (QAP). - - [SNARKs vs. STARKs](https://zkhack.dev/whiteboard/module-four/) - -Related Papers -[Pinocchio: Nearly Practical Verifiable Computation](https://eprint.iacr.org/2013/279.pdf) - -## 5. STARKs (Scalable Transparent ARguments of Knowledge) - -### Key Concepts: -- Fundamentals of STARKs: Differences with SNARKs and applications. - - [ZK-STARKs: Scalable Transparent Zero Knowledge Proofs](https://eprint.iacr.org/2018/046.pdf) - - [Diving into Starks](https://www.youtube.com/watch?v=cDzTm3clrEo) - - Multipart tutorial by Vitalik Buterin [I](https://vitalik-eth-limo.translate.goog/general/2017/11/09/starks_part_1.html?_x_tr_sl=en&_x_tr_tl=es&_x_tr_hl=es-419&_x_tr_pto=sc) [II](https://vitalik.eth.limo/general/2017/11/22/starks_part_2.html) & [III](https://vitalik.eth.limo/general/2018/07/21/starks_part_3.html) -- Protocols and Security in STARKs: FRI (Fast Reed-Solomon IOPP) and AIR (Algebraic Intermediate Representation) - -# Other learning resources - -This list contains papers, videos, books, and links to resources that we found useful to learn about zero-knowledge proofs and cryptography. The list is by no means exhaustive and we will be updating it. - -## Videos - -- [ZK Whiteboard](https://zkhack.dev/whiteboard/) -- [All the MATH you need to understand SNARKs and STARKs](https://www.youtube.com/playlist?list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ) - -## Books - -- [Thaler - Proofs, Arguments and Zero-knowledge](https://people.cs.georgetown.edu/jthaler/ProofsArgsAndZK.pdf) - -## Papers - -- [Pinocchio](https://eprint.iacr.org/2013/279.pdf) -- [Plonk](https://eprint.iacr.org/2019/953.pdf) -- [Square Span Programs with Applications to Succinct NIZK Arguments](https://eprint.iacr.org/2014/718.pdf) -- [KZG Polynomial Commitment Scheme](https://cacr.uwaterloo.ca/techreports/2010/cacr2010-10.pdf) - -## Courses -- [Modern Zero Knowledge Cryptography - MIT IAP 2023](https://zkiap.com) -- [Zero Knowledge Proofs](https://zk-learning.org) Dan Boneh, Shafi Goldwasser, Dawn Song, Justin Thaler & Yupeng Zhang - -## Links - -- [STARK-101 - Python](https://starkware.co/stark-101/) -- [BabySnark Protocol](https://github.com/lambdaclass/lambdaworks/tree/main/examples/baby-snark) diff --git a/bootcamp/sparkling_water_0b10.md b/bootcamp/sparkling_water_0b10.md deleted file mode 100644 index 03d7d1a64..000000000 --- a/bootcamp/sparkling_water_0b10.md +++ /dev/null @@ -1,115 +0,0 @@ -# Sparkling Water Bootcamp in Cryptography 01b0 - -## About - -This is the second edition of the Sparkling Water Bootcamp in Cryptography. It is intended to provide an overview of proof systems and some topic in cryptography. It has a duration of 8 weeks of lectures, exercises and coding practice. - -## Intended roadmap - -The roadmap is dynamic and may change as the bootcamp progresses. - -### Week 1 - Fundamentals I - -- Math preliminaries: groups, rings and fields -- Finite fields -- RSA cryptosystem -- Univariate polynomials over finite fields -- Shamir secret sharing -- Examples of commonly used finite fields in Cryptography - -#### Learning materials: - -- [An introduction to mathematical cryptography](https://books.google.com.ar/books/about/An_Introduction_to_Mathematical_Cryptogr.html?id=BHuTQgAACAAJ&source=kp_book_description&redir_esc=y) - Chapter 1 & 3. -- [The MiniGoldilocks prime](https://xn--2-umb.com/22/goldilocks/) -- [Summary on Montgomery arithmetic](https://eprint.iacr.org/2017/1057.pdf) -- [Mersenne primes](https://eprint.iacr.org/2023/824.pdf) -- [Binary fields by Vitalik](https://vitalik.eth.limo/general/2024/04/29/binius.html) -- [Finite Fields](https://www.youtube.com/watch?v=MAhmV_omOwA&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=8) -- [Constructing finite fields](https://www.youtube.com/watch?v=JPiXFn9WA5Y&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=6) -- [Cyclic groups](https://www.youtube.com/watch?v=UIhhs38IAGM&list=PLFX2cij7c2PynTNWDBzmzaD6ij170ILbQ&index=3) - -#### Motivation - -- [Mersenne primes' performance in STWO](https://www.youtube.com/watch?v=_eha0QqAbIA) -- [Circle STARKs](https://www.youtube.com/watch?v=NAhLYMysSdk&list=PLj80z0cJm8QFy2umHqu77a8dbZSqpSH54&index=17) -- [Binius](https://www.youtube.com/watch?v=rgRWcWOll0w&list=PLj80z0cJm8QFy2umHqu77a8dbZSqpSH54&index=4) - -#### Exercises - -- Find all the multiplicative subgroups of the multiplicative group of integers modulo 17. -- Define a field in lambdaworks. -- Write simple code using the different field operations in lambdaworks. -- Implement a basic version of Shamir secret sharing. - -### Week 2 - Fundamentals II - -- Elliptic curves over finite fields. -- Diffie-Hellman key exchange -- Small subgroup attacks -- Collision-resistant hash functions -- Merkle trees -- KZG polynomial commitment scheme - -#### Recommended material - -- [Moonmath Manual](https://leastauthority.com/community-matters/moonmath-manual/) - Chapter 5, until 5.3 -- [Programming Bitcoin](https://books.google.fr/books/about/Programming_Bitcoin.html?id=O2aHDwAAQBAJ&source=kp_book_description&redir_esc=y) - Chapters 2 & 3. -- [Introduction to Mathematical Cryptography](https://books.google.com.ar/books/about/An_Introduction_to_Mathematical_Cryptogr.html?id=BHuTQgAACAAJ&source=kp_book_description&redir_esc=y) - Chapter 5 until 5.5 -- [Serious Cryptography](https://books.google.com.ar/books/about/Serious_Cryptography.html?id=1D-QEAAAQBAJ&source=kp_book_description&redir_esc=y) - Chapters 11 & 12. -- [KZG basics and application to Mina Bridge](https://blog.lambdaclass.com/mina-to-ethereum-bridge/) - -### Week 3 - BabySNARK - -- SNARKs - fundamentals. -- Elliptic curve pairings. -- KZG commitment scheme. -- Square span programs -- BabySNARK -- Field extensions - -#### Reading material - -- [Pairings for beginners](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) -- [BabySNARK](https://github.com/lambdaclass/lambdaworks/tree/main/examples/baby-snark) - -#### Exercises - -- Create a simple boolean circuit, generate the square constraint system and generate a proof of execution and verify it. -- Explain what polynomial commitments are and how KZG commitment works. -- Create a false proof if you know the value of the parameter beta. -- Explain the drawbacks of a trusted setup. -- Solve [exercise 2 in lambdaworks](https://github.com/lambdaclass/lambdaworks/tree/main/exercises/challenge_2) - -### Week 4 - STARKs and the FRI protocol - -- Algebraic intermediate representation (AIR) -- FRI protocol -- STARK protocol -- Comparison between virtual machines - -### Week 5 - Groth 16 - -- R1CS -- Quadratic arithmetic programs -- Groth 16 - -### Week 6 - Plonk - -- Plonkish arithmetization -- Permutation checks -- Different flavors of Plonk - -### Week 7 - Lookup arguments and folding schemes - -- Lookup arguments -- Plookup -- LogUp -- Folding schemes -- Proof-carrying data (PCD) -- Nova - -### Week 8 - More advanced topics - -TBD - -## Challenges and exercises diff --git a/crypto/src/merkle_tree/merkle.rs b/crypto/src/merkle_tree/merkle.rs index 9f4b126d1..bbfe89bf7 100644 --- a/crypto/src/merkle_tree/merkle.rs +++ b/crypto/src/merkle_tree/merkle.rs @@ -123,7 +123,7 @@ mod tests { let values: Vec = vec![FE::new(1)]; // Single element let merkle_tree = MerkleTree::>::build(&values).unwrap(); - assert_eq!(merkle_tree.root, FE::new(4)); // Adjusted expected value + assert_eq!(merkle_tree.root, FE::new(2)); // Adjusted expected value } #[test] diff --git a/crypto/src/merkle_tree/proof.rs b/crypto/src/merkle_tree/proof.rs index 6f875fa6a..65e37555a 100644 --- a/crypto/src/merkle_tree/proof.rs +++ b/crypto/src/merkle_tree/proof.rs @@ -163,8 +163,8 @@ mod tests { let merkle_tree = MerkleTree::>::build(&values).unwrap(); // Update the expected root value based on the actual logic of TestBackend - // For example, if combining two `1`s results in `4`, update this accordingly - let expected_root = FE::new(4); // Assuming combining two `1`s results in `4` + // For example, in this case hashing a single `1` results in `2` + let expected_root = FE::new(2); // Assuming hashing a `1`s results in `2` assert_eq!( merkle_tree.root, expected_root, "The root of the Merkle tree does not match the expected value." diff --git a/crypto/src/merkle_tree/utils.rs b/crypto/src/merkle_tree/utils.rs index 33740780e..1a32d205a 100644 --- a/crypto/src/merkle_tree/utils.rs +++ b/crypto/src/merkle_tree/utils.rs @@ -29,13 +29,12 @@ pub fn complete_until_power_of_two(mut values: Vec) -> Vec { } // ! NOTE ! -// We in this function we say 2^0 = 1 is not a power of two when it is infact true. We -// need this to maintain that the smallest tree at two leaves counts and we could not find -// a name that wasn't overly verbose. In the case of a single value being present in a leaf node -// this indicates we pad to next power of two (i.e. 2). The function is private and is only used -// to ensure the tree has a power of 2 number of leaves. +// In this function we say 2^0 = 1 is a power of two. +// In turn, this makes the smallest tree of one leaf, possible. +// The function is private and is only used to ensure the tree +// has a power of 2 number of leaves. fn is_power_of_two(x: usize) -> bool { - (x > 1) && ((x & (x - 1)) == 0) + (x & (x - 1)) == 0 } // ! CAUTION ! @@ -124,9 +123,8 @@ mod tests { let mut expected_leaves = vec![FE::new(2)]; expected_leaves.extend([FE::new(2)]); - assert_eq!(hashed_leaves.len(), 2); + assert_eq!(hashed_leaves.len(), 1); assert_eq!(hashed_leaves[0], expected_leaves[0]); - assert_eq!(hashed_leaves[1], expected_leaves[1]); } const ROOT: usize = 0; diff --git a/math/README.md b/math/README.md index 81f6f8c66..e5e0830a0 100644 --- a/math/README.md +++ b/math/README.md @@ -13,9 +13,9 @@ lambdaworks-math = "0.8.0" ## Structure This crate contains all the relevant mathematical building blocks needed for proof systems and cryptography. The main parts are: -- [Finite Fields](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/field) -- [Elliptic curves](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve) -- [Polynomials - univariate and multivariate](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/polynomial) +- [Finite Fields](./src/field/README.md) +- [Elliptic curves](./src/elliptic_curve/README.md) +- [Polynomials - univariate and multivariate](./src/polynomial/README.md) - [Large unsigned integers](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/unsigned_integer) - [Fast Fourier Transform](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/fft) - [Optimized Multiscalar Multiplication](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/msm) diff --git a/math/benches/criterion_elliptic_curve.rs b/math/benches/criterion_elliptic_curve.rs index 3812d74c3..f9bffc781 100644 --- a/math/benches/criterion_elliptic_curve.rs +++ b/math/benches/criterion_elliptic_curve.rs @@ -10,6 +10,6 @@ use elliptic_curves::{ criterion_group!( name = elliptic_curve_benches; config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bn_254_elliptic_curve_benchmarks,bls12_377_elliptic_curve_benchmarks,bls12_381_elliptic_curve_benchmarks + targets = bn_254_elliptic_curve_benchmarks,bls12_381_elliptic_curve_benchmarks,bls12_377_elliptic_curve_benchmarks ); criterion_main!(elliptic_curve_benches); diff --git a/math/benches/criterion_field.rs b/math/benches/criterion_field.rs index 1c21822de..6e41cbb4b 100644 --- a/math/benches/criterion_field.rs +++ b/math/benches/criterion_field.rs @@ -2,7 +2,7 @@ use criterion::{criterion_group, criterion_main, Criterion}; use pprof::criterion::{Output, PProfProfiler}; mod fields; -use fields::mersenne31::mersenne31_ops_benchmarks; +use fields::mersenne31::{mersenne31_extension_ops_benchmarks, mersenne31_ops_benchmarks}; use fields::mersenne31_montgomery::mersenne31_mont_ops_benchmarks; use fields::{ stark252::starkfield_ops_benchmarks, u64_goldilocks::u64_goldilocks_ops_benchmarks, @@ -12,6 +12,6 @@ use fields::{ criterion_group!( name = field_benches; config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = starkfield_ops_benchmarks, mersenne31_ops_benchmarks, mersenne31_mont_ops_benchmarks, u64_goldilocks_ops_benchmarks, u64_goldilocks_montgomery_ops_benchmarks + targets = mersenne31_ops_benchmarks, mersenne31_extension_ops_benchmarks, mersenne31_mont_ops_benchmarks, starkfield_ops_benchmarks, u64_goldilocks_ops_benchmarks, u64_goldilocks_montgomery_ops_benchmarks ); criterion_main!(field_benches); diff --git a/math/benches/elliptic_curves/bls12_381.rs b/math/benches/elliptic_curves/bls12_381.rs index d33e8d2ca..452480697 100644 --- a/math/benches/elliptic_curves/bls12_381.rs +++ b/math/benches/elliptic_curves/bls12_381.rs @@ -4,7 +4,9 @@ use lambdaworks_math::{ elliptic_curve::{ short_weierstrass::{ curves::bls12_381::{ - curve::BLS12381Curve, pairing::BLS12381AtePairing, twist::BLS12381TwistCurve, + curve::BLS12381Curve, + pairing::{final_exponentiation, miller, BLS12381AtePairing}, + twist::BLS12381TwistCurve, }, traits::Compress, }, @@ -24,6 +26,8 @@ pub fn bls12_381_elliptic_curve_benchmarks(c: &mut Criterion) { let a_g2 = BLS12381TwistCurve::generator(); let b_g2 = BLS12381TwistCurve::generator(); + let miller_loop_output = miller(&a_g2, &a_g1); + let mut group = c.benchmark_group("BLS12-381 Ops"); group.significance_level(0.1).sample_size(10000); group.throughput(criterion::Throughput::Elements(1)); @@ -93,4 +97,14 @@ pub fn bls12_381_elliptic_curve_benchmarks(c: &mut Criterion) { )) }); }); + + // Miller + group.bench_function("Miller", |bencher| { + bencher.iter(|| black_box(miller(black_box(&a_g2), black_box(&a_g1)))) + }); + + // Final Exponentiation Optimized + group.bench_function("Final Exponentiation", |bencher| { + bencher.iter(|| black_box(final_exponentiation(black_box(&miller_loop_output)))) + }); } diff --git a/math/benches/fields/mersenne31.rs b/math/benches/fields/mersenne31.rs index 99e3921a5..e8d99d1c2 100644 --- a/math/benches/fields/mersenne31.rs +++ b/math/benches/fields/mersenne31.rs @@ -1,10 +1,18 @@ use std::hint::black_box; use criterion::Criterion; -use lambdaworks_math::field::{element::FieldElement, fields::mersenne31::field::Mersenne31Field}; +use lambdaworks_math::field::{ + element::FieldElement, + fields::mersenne31::{ + extensions::{Degree2ExtensionField, Degree4ExtensionField}, + field::Mersenne31Field, + }, +}; use rand::random; pub type F = FieldElement; +pub type Fp2E = FieldElement; +pub type Fp4E = FieldElement; #[inline(never)] #[no_mangle] @@ -17,6 +25,60 @@ pub fn rand_field_elements(num: usize) -> Vec<(F, F)> { result } +//TODO: Check if this is the correct way to bench. +pub fn rand_fp4e(num: usize) -> Vec<(Fp4E, Fp4E)> { + let mut result = Vec::with_capacity(num); + for _ in 0..result.capacity() { + result.push(( + Fp4E::new([ + Fp2E::new([F::new(random()), F::new(random())]), + Fp2E::new([F::new(random()), F::new(random())]), + ]), + Fp4E::new([ + Fp2E::new([F::new(random()), F::new(random())]), + Fp2E::new([F::new(random()), F::new(random())]), + ]), + )); + } + result +} + +pub fn mersenne31_extension_ops_benchmarks(c: &mut Criterion) { + let input: Vec> = [1000000].into_iter().map(rand_fp4e).collect::>(); + + let mut group = c.benchmark_group("Mersenne31 Fp4 operations"); + + for i in input.clone().into_iter() { + group.bench_with_input(format!("Mul of Fp4 {:?}", &i.len()), &i, |bench, i| { + bench.iter(|| { + for (x, y) in i { + black_box(black_box(x) * black_box(y)); + } + }); + }); + } + + for i in input.clone().into_iter() { + group.bench_with_input(format!("Square of Fp4 {:?}", &i.len()), &i, |bench, i| { + bench.iter(|| { + for (x, _) in i { + black_box(black_box(x).square()); + } + }); + }); + } + + for i in input.clone().into_iter() { + group.bench_with_input(format!("Inv of Fp4 {:?}", &i.len()), &i, |bench, i| { + bench.iter(|| { + for (x, _) in i { + black_box(black_box(x).inv().unwrap()); + } + }); + }); + } +} + pub fn mersenne31_ops_benchmarks(c: &mut Criterion) { let input: Vec> = [1, 10, 100, 1000, 10000, 100000, 1000000] .into_iter() diff --git a/math/src/elliptic_curve/point.rs b/math/src/elliptic_curve/point.rs index b55b541e1..7652981c5 100644 --- a/math/src/elliptic_curve/point.rs +++ b/math/src/elliptic_curve/point.rs @@ -42,7 +42,7 @@ impl ProjectivePoint { let [x, y, z] = self.coordinates(); // If it's the point at infinite if z == &FieldElement::zero() { - // We make sure all the points in the infinite have the same values + // We make sure all the points at infinite have the same values return Self::new([ FieldElement::zero(), FieldElement::one(), @@ -63,7 +63,80 @@ impl PartialEq for ProjectivePoint { } impl Eq for ProjectivePoint {} +#[derive(Debug, Clone)] + +pub struct JacobianPoint { + pub value: [FieldElement; 3], +} + +impl JacobianPoint { + /// Creates an elliptic curve point giving the Jacobian [x: y: z] coordinates. + pub const fn new(value: [FieldElement; 3]) -> Self { + Self { value } + } + /// Returns the `x` coordinate of the point. + pub fn x(&self) -> &FieldElement { + &self.value[0] + } + + /// Returns the `y` coordinate of the point. + pub fn y(&self) -> &FieldElement { + &self.value[1] + } + + /// Returns the `z` coordinate of the point. + pub fn z(&self) -> &FieldElement { + &self.value[2] + } + + /// Returns a tuple [x, y, z] with the coordinates of the point. + pub fn coordinates(&self) -> &[FieldElement; 3] { + &self.value + } + + pub fn to_affine(&self) -> Self { + let [x, y, z] = self.coordinates(); + // If it's the point at infinite + if z == &FieldElement::zero() { + // We make sure all the points at infinite have the same values + return Self::new([ + FieldElement::one(), + FieldElement::one(), + FieldElement::zero(), + ]); + }; + let inv_z = z.inv().unwrap(); + let inv_z_square = inv_z.square(); + let inv_z_cube = &inv_z_square * &inv_z; + JacobianPoint::new([x * inv_z_square, y * inv_z_cube, FieldElement::one()]) + } +} + +impl PartialEq for JacobianPoint { + fn eq(&self, other: &Self) -> bool { + // In Jacobian coordinates, the equality of two points is defined as: + // X1 * Z2^2 == X2 * Z1^2 y Y1 * Z2^3 == Y2 * Z1^3 + + let [px, py, pz] = self.coordinates(); + let [qx, qy, qz] = other.coordinates(); + + let zp_sq = pz.square(); + let zq_sq = qz.square(); + + let zp_cu = &zp_sq * pz; + let zq_cu = &zq_sq * qz; + + let xp_zq_sq = px * zq_sq; + let xq_zp_sq = qx * zp_sq; + + let yp_zq_cu = py * zq_cu; + let yq_zp_cu = qy * zp_cu; + + (xp_zq_sq == xq_zp_sq) && (yp_zq_cu == yq_zp_cu) + } +} +impl Eq for JacobianPoint {} #[cfg(test)] mod tests { use crate::cyclic_group::IsGroup; diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs index c324b35de..efa52bdbc 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs @@ -1,10 +1,25 @@ -use super::field_extension::BLS12377PrimeField; +use super::{ + field_extension::{BLS12377PrimeField, Degree2ExtensionField}, + twist::BLS12377TwistCurve, +}; +use crate::cyclic_group::IsGroup; use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint; use crate::elliptic_curve::traits::IsEllipticCurve; +use crate::unsigned_integer::element::U256; + use crate::{ elliptic_curve::short_weierstrass::traits::IsShortWeierstrass, field::element::FieldElement, }; +pub const SUBGROUP_ORDER: U256 = + U256::from_hex_unchecked("12ab655e9a2ca55660b44d1e5c37b00159aa76fed00000010a11800000000001"); + +pub const CURVE_COFACTOR: U256 = + U256::from_hex_unchecked("0x30631250834960419227450344600217059328"); + +pub type BLS12377FieldElement = FieldElement; +pub type BLS12377TwistCurveFieldElement = FieldElement; + /// The description of the curve. #[derive(Clone, Debug)] pub struct BLS12377Curve; @@ -32,6 +47,71 @@ impl IsShortWeierstrass for BLS12377Curve { } } +/// This is equal to the frobenius trace of the BLS12 377 curve minus one or seed value z. +pub const MILLER_LOOP_CONSTANT: u64 = 0x8508c00000000001; + +/// 𝛽 : primitive cube root of unity of πΉβ‚š that Β§satisfies the minimal equation +/// 𝛽² + 𝛽 + 1 = 0 mod 𝑝 +pub const CUBE_ROOT_OF_UNITY_G1: BLS12377FieldElement = FieldElement::from_hex_unchecked( + "0x1ae3a4617c510eabc8756ba8f8c524eb8882a75cc9bc8e359064ee822fb5bffd1e945779fffffffffffffffffffffff", +); + +/// x-coordinate of 𝜁 ∘ πœ‹_q ∘ 𝜁⁻¹, where 𝜁 is the isomorphism u:E'(π”½β‚šβ‚†) βˆ’> E(π”½β‚šβ‚β‚‚) from the twist to E +pub const ENDO_U: BLS12377TwistCurveFieldElement = + BLS12377TwistCurveFieldElement::const_from_raw([ + FieldElement::from_hex_unchecked( + "9B3AF05DD14F6EC619AAF7D34594AABC5ED1347970DEC00452217CC900000008508C00000000002", + ), + FieldElement::from_hex_unchecked("0"), + ]); + +/// y-coordinate of 𝜁 ∘ πœ‹_q ∘ 𝜁⁻¹, where 𝜁 is the isomorphism u:E'(π”½β‚šβ‚†) βˆ’> E(π”½β‚šβ‚β‚‚) from the twist to E +pub const ENDO_V: BLS12377TwistCurveFieldElement = + BLS12377TwistCurveFieldElement::const_from_raw([ + FieldElement::from_hex_unchecked("1680A40796537CAC0C534DB1A79BEB1400398F50AD1DEC1BCE649CF436B0F6299588459BFF27D8E6E76D5ECF1391C63"), + FieldElement::from_hex_unchecked("0"), + ]); + +impl ShortWeierstrassProjectivePoint { + /// Returns πœ™(P) = (π‘₯, 𝑦) β‡’ (𝛽π‘₯, 𝑦), where 𝛽 is the Cube Root of Unity in the base prime field + /// https://eprint.iacr.org/2022/352.pdf 2 Preliminaries + fn phi(&self) -> Self { + let mut a = self.clone(); + a.0.value[0] = a.x() * CUBE_ROOT_OF_UNITY_G1; + a + } + + /// πœ™(P) = βˆ’π‘’Β²P + /// https://eprint.iacr.org/2022/352.pdf 4.3 Prop. 4 + pub fn is_in_subgroup(&self) -> bool { + self.operate_with_self(MILLER_LOOP_CONSTANT) + .operate_with_self(MILLER_LOOP_CONSTANT) + .neg() + == self.phi() + } +} + +impl ShortWeierstrassProjectivePoint { + /// πœ“(P) = 𝜁 ∘ πœ‹β‚š ∘ 𝜁⁻¹, where 𝜁 is the isomorphism u:E'(π”½β‚šβ‚†) βˆ’> E(π”½β‚šβ‚β‚‚) from the twist to E,, πœ‹β‚š is the p-power frobenius endomorphism + /// and πœ“ satisifies minmal equation 𝑋² + 𝑑𝑋 + π‘ž = 𝑂 + /// https://eprint.iacr.org/2022/352.pdf 4.2 (7) + /// ψ(P) = (ψ_x * conjugate(x), ψ_y * conjugate(y), conjugate(z)) + fn psi(&self) -> Self { + let [x, y, z] = self.coordinates(); + Self::new([ + x.conjugate() * ENDO_U, + y.conjugate() * ENDO_V, + z.conjugate(), + ]) + } + + /// πœ“(P) = 𝑒P, where 𝑒 = SEED of the curve + /// https://eprint.iacr.org/2022/352.pdf 4.2 + pub fn is_in_subgroup(&self) -> bool { + self.psi() == self.operate_with_self(MILLER_LOOP_CONSTANT) + } +} + #[cfg(test)] mod tests { use super::*; @@ -43,17 +123,18 @@ mod tests { use super::BLS12377Curve; #[allow(clippy::upper_case_acronyms)] - type FEE = FieldElement; + type FpE = FieldElement; + type Fp2 = FieldElement; fn point_1() -> ShortWeierstrassProjectivePoint { - let x = FEE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea"); - let y = FEE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2"); + let x = FpE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea"); + let y = FpE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2"); BLS12377Curve::create_point_from_affine(x, y).unwrap() } fn point_1_times_5() -> ShortWeierstrassProjectivePoint { - let x = FEE::new_base("3c852d5aab73fbb51e57fbf5a0a8b5d6513ec922b2611b7547bfed74cba0dcdfc3ad2eac2733a4f55d198ec82b9964"); - let y = FEE::new_base("a71425e68e55299c64d7eada9ae9c3fb87a9626b941d17128b64685fc07d0e635f3c3a512903b4e0a43e464045967b"); + let x = FpE::new_base("3c852d5aab73fbb51e57fbf5a0a8b5d6513ec922b2611b7547bfed74cba0dcdfc3ad2eac2733a4f55d198ec82b9964"); + let y = FpE::new_base("a71425e68e55299c64d7eada9ae9c3fb87a9626b941d17128b64685fc07d0e635f3c3a512903b4e0a43e464045967b"); BLS12377Curve::create_point_from_affine(x, y).unwrap() } @@ -101,9 +182,9 @@ mod tests { let point_1 = point_1().to_affine(); // Create point 2 - let x = FEE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea") * FEE::from(2); - let y = FEE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2") * FEE::from(2); - let z = FEE::from(2); + let x = FpE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea") * FpE::from(2); + let y = FpE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2") * FpE::from(2); + let z = FpE::from(2); let point_2 = ShortWeierstrassProjectivePoint::::new([x, y, z]); let first_algorithm_result = point_2.operate_with(&point_1).to_affine(); @@ -115,15 +196,15 @@ mod tests { #[test] fn create_valid_point_works() { let p = point_1(); - assert_eq!(*p.x(), FEE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea")); - assert_eq!(*p.y(), FEE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2")); - assert_eq!(*p.z(), FEE::new_base("1")); + assert_eq!(*p.x(), FpE::new_base("134e4cc122cb62a06767fb98e86f2d5f77e2a12fefe23bb0c4c31d1bd5348b88d6f5e5dee2b54db4a2146cc9f249eea")); + assert_eq!(*p.y(), FpE::new_base("17949c29effee7a9f13f69b1c28eccd78c1ed12b47068836473481ff818856594fd9c1935e3d9e621901a2d500257a2")); + assert_eq!(*p.z(), FpE::new_base("1")); } #[test] fn create_invalid_points_panics() { assert_eq!( - BLS12377Curve::create_point_from_affine(FEE::from(1), FEE::from(1)).unwrap_err(), + BLS12377Curve::create_point_from_affine(FpE::from(1), FpE::from(1)).unwrap_err(), EllipticCurveError::InvalidPoint ) } @@ -144,4 +225,36 @@ mod tests { g.operate_with_self(3_u16) ); } + + #[test] + fn generator_g1_is_in_subgroup() { + let g = BLS12377Curve::generator(); + assert!(g.is_in_subgroup()) + } + + #[test] + fn point1_is_in_subgroup() { + let p = point_1(); + assert!(p.is_in_subgroup()) + } + + #[test] + fn arbitrary_g1_point_is_in_subgroup() { + let g = BLS12377Curve::generator().operate_with_self(32u64); + assert!(g.is_in_subgroup()) + } + #[test] + fn generator_g2_is_in_subgroup() { + let g = BLS12377TwistCurve::generator(); + assert!(g.is_in_subgroup()) + } + + #[test] + fn g2_conjugate_works() { + let a = Fp2::zero(); + let mut expected = a.conjugate(); + expected = expected.conjugate(); + + assert_eq!(a, expected); + } } diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs index 32f9d465d..96c227ddb 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs @@ -1,10 +1,18 @@ use crate::field::{ element::FieldElement, + errors::FieldError, + extensions::{ + cubic::{CubicExtensionField, HasCubicNonResidue}, + quadratic::{HasQuadraticNonResidue, QuadraticExtensionField}, + }, fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, + traits::{IsField, IsSubFieldOf}, }; +use crate::traits::ByteConversion; use crate::unsigned_integer::element::U384; pub const BLS12377_PRIME_FIELD_ORDER: U384 = U384::from_hex_unchecked("1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508c00000000001"); +pub const FP2_RESIDUE: FieldElement =FieldElement::from_hex_unchecked("0x1ae3a4617c510eac63b05c06ca1493b1a22d9f300f5138f1ef3622fba094800170b5d44300000008508bffffffffffc"); // FPBLS12377 #[derive(Clone, Debug)] @@ -15,8 +23,340 @@ impl IsModulus for BLS12377FieldModulus { pub type BLS12377PrimeField = MontgomeryBackendPrimeField; +#[derive(Clone, Debug)] +pub struct Degree2ExtensionField; + +impl IsField for Degree2ExtensionField { + type BaseType = [FieldElement; 2]; + /// Returns the component wise addition of `a` and `b` + /// Returns the component wise addition of `a` and `b` + fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [&a[0] + &b[0], &a[1] + &b[1]] + } + + /// Returns the multiplication of `a` and `b` using the following + /// equation: + /// (a0 + a1 * t) * (b0 + b1 * t) = a0 * b0 + a1 * b1 * Self::residue() + (a0 * b1 + a1 * b0) * t + /// where `t.pow(2)` equals `Q::residue()`. + fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + let a0b0 = &a[0] * &b[0]; + let a1b1 = &a[1] * &b[1]; + let z = (&a[0] + &a[1]) * (&b[0] + &b[1]); + [&a0b0 + &a1b1 * FP2_RESIDUE, z - a0b0 - a1b1] + } + + fn square(a: &Self::BaseType) -> Self::BaseType { + let [a0, a1] = a; + let v0 = a0 * a1; + let c0 = (a0 + a1) * (a0 + &FP2_RESIDUE * a1) - &v0 - FP2_RESIDUE * &v0; + let c1 = &v0 + &v0; + [c0, c1] + } + /// Returns the component wise subtraction of `a` and `b` + fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [&a[0] - &b[0], &a[1] - &b[1]] + } + + /// Returns the component wise negation of `a` + fn neg(a: &Self::BaseType) -> Self::BaseType { + [-&a[0], -&a[1]] + } + + /// Returns the multiplicative inverse of `a` + /// This uses the equality `(a0 + a1 * t) * (a0 - a1 * t) = a0.pow(2) - a1.pow(2) * Q::residue()` + fn inv(a: &Self::BaseType) -> Result { + let q: FieldElement = -FieldElement::from(5); + let inv_norm = (a[0].pow(2_u64) - q * a[1].pow(2_u64)).inv()?; + Ok([&a[0] * &inv_norm, -&a[1] * inv_norm]) + } + + /// Returns the division of `a` and `b` + fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + ::mul(a, &Self::inv(b).unwrap()) + } + + /// Returns a boolean indicating whether `a` and `b` are equal component wise. + fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { + a[0] == b[0] && a[1] == b[1] + } + + /// Returns the additive neutral element of the field extension. + fn zero() -> Self::BaseType { + [FieldElement::zero(), FieldElement::zero()] + } + + /// Returns the multiplicative neutral element of the field extension. + fn one() -> Self::BaseType { + [FieldElement::one(), FieldElement::zero()] + } + + /// Returns the element `x * 1` where 1 is the multiplicative neutral element. + fn from_u64(x: u64) -> Self::BaseType { + [FieldElement::from(x), FieldElement::zero()] + } + + /// Takes as input an element of BaseType and returns the internal representation + /// of that element in the field. + /// Note: for this case this is simply the identity, because the components + /// already have correct representations. + fn from_base_type(x: Self::BaseType) -> Self::BaseType { + x + } +} + +impl IsSubFieldOf for BLS12377PrimeField { + fn mul( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let c0 = FieldElement::from_raw(::mul(a, b[0].value())); + let c1 = FieldElement::from_raw(::mul(a, b[1].value())); + [c0, c1] + } + + fn add( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let c0 = FieldElement::from_raw(::add(a, b[0].value())); + let c1 = FieldElement::from_raw(*b[1].value()); + [c0, c1] + } + + fn div( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let b_inv = Degree2ExtensionField::inv(b).unwrap(); + >::mul(a, &b_inv) + } + + fn sub( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let c0 = FieldElement::from_raw(::sub(a, b[0].value())); + let c1 = FieldElement::from_raw(::neg(b[1].value())); + [c0, c1] + } + + fn embed(a: Self::BaseType) -> ::BaseType { + [FieldElement::from_raw(a), FieldElement::zero()] + } + + #[cfg(feature = "alloc")] + fn to_subfield_vec( + b: ::BaseType, + ) -> alloc::vec::Vec { + b.into_iter().map(|x| x.to_raw()).collect() + } +} + +impl ByteConversion for FieldElement { + #[cfg(feature = "alloc")] + fn to_bytes_be(&self) -> alloc::vec::Vec { + let mut byte_slice = ByteConversion::to_bytes_be(&self.value()[0]); + byte_slice.extend(ByteConversion::to_bytes_be(&self.value()[1])); + byte_slice + } + + #[cfg(feature = "alloc")] + fn to_bytes_le(&self) -> alloc::vec::Vec { + let mut byte_slice = ByteConversion::to_bytes_le(&self.value()[0]); + byte_slice.extend(ByteConversion::to_bytes_le(&self.value()[1])); + byte_slice + } + + fn from_bytes_be(bytes: &[u8]) -> Result + where + Self: core::marker::Sized, + { + const BYTES_PER_FIELD: usize = 48; + let x0 = FieldElement::from_bytes_be(&bytes[0..BYTES_PER_FIELD])?; + let x1 = FieldElement::from_bytes_be(&bytes[BYTES_PER_FIELD..BYTES_PER_FIELD * 2])?; + Ok(Self::new([x0, x1])) + } + + fn from_bytes_le(bytes: &[u8]) -> Result + where + Self: core::marker::Sized, + { + const BYTES_PER_FIELD: usize = 48; + let x0 = FieldElement::from_bytes_le(&bytes[0..BYTES_PER_FIELD])?; + let x1 = FieldElement::from_bytes_le(&bytes[BYTES_PER_FIELD..BYTES_PER_FIELD * 2])?; + Ok(Self::new([x0, x1])) + } +} + +impl FieldElement { + pub fn new_base(a_hex: &str) -> Self { + Self::new([FieldElement::new(U384::from(a_hex)), FieldElement::zero()]) + } + + pub fn conjugate(&self) -> Self { + let [a, b] = self.value(); + Self::new([a.clone(), -b]) + } +} + +#[derive(Debug, Clone)] +pub struct BLS12377Residue; +impl HasQuadraticNonResidue for BLS12377Residue { + fn residue() -> FieldElement { + FP2_RESIDUE + } +} + +#[derive(Debug, Clone)] +pub struct LevelTwoResidue; + +impl HasCubicNonResidue for LevelTwoResidue { + fn residue() -> FieldElement { + FieldElement::new([ + FieldElement::new(U384::from("0")), + -FieldElement::new(U384::from("1")), + ]) + } +} + +pub type Degree6ExtensionField = CubicExtensionField; + +#[derive(Debug, Clone)] +pub struct LevelThreeResidue; +impl HasQuadraticNonResidue for LevelThreeResidue { + fn residue() -> FieldElement { + FieldElement::new([ + FieldElement::zero(), + FieldElement::one(), + FieldElement::zero(), + ]) + } +} + +/// We define Fp12 = Fp6 [w] / (w^2 - v) +pub type Degree12ExtensionField = QuadraticExtensionField; + +impl FieldElement { + pub fn new_base(a_hex: &str) -> Self { + Self::new([ + FieldElement::new([FieldElement::new(U384::from(a_hex)), FieldElement::zero()]), + FieldElement::zero(), + FieldElement::zero(), + ]) + } +} + impl FieldElement { pub fn new_base(a_hex: &str) -> Self { - Self::new(U384::from_hex_unchecked(a_hex)) + Self::new(U384::from(a_hex)) + } +} +impl FieldElement { + pub fn new_base(a_hex: &str) -> Self { + Self::new([ + FieldElement::::new_base(a_hex), + FieldElement::zero(), + ]) + } + + pub fn from_coefficients(coefficients: &[&str; 12]) -> Self { + FieldElement::::new([ + FieldElement::new([ + FieldElement::new([ + FieldElement::new(U384::from(coefficients[0])), + FieldElement::new(U384::from(coefficients[1])), + ]), + FieldElement::new([ + FieldElement::new(U384::from(coefficients[2])), + FieldElement::new(U384::from(coefficients[3])), + ]), + FieldElement::new([ + FieldElement::new(U384::from(coefficients[4])), + FieldElement::new(U384::from(coefficients[5])), + ]), + ]), + FieldElement::new([ + FieldElement::new([ + FieldElement::new(U384::from(coefficients[6])), + FieldElement::new(U384::from(coefficients[7])), + ]), + FieldElement::new([ + FieldElement::new(U384::from(coefficients[8])), + FieldElement::new(U384::from(coefficients[9])), + ]), + FieldElement::new([ + FieldElement::new(U384::from(coefficients[10])), + FieldElement::new(U384::from(coefficients[11])), + ]), + ]), + ]) + } +} + +#[cfg(test)] +mod tests { + + use super::*; + type FpE = FieldElement; + type Fp2E = FieldElement; + type Fp6E = FieldElement; + type Fp12E = FieldElement; + + #[test] + fn embed_base_field_with_degree_2_extension() { + let a = FpE::from(3); + let a_extension = Fp2E::from(3); + assert_eq!(a.to_extension::(), a_extension); + } + #[test] + fn add_base_field_with_degree_2_extension() { + let a = FpE::from(3); + let a_extension = Fp2E::from(3); + let b = Fp2E::from(2); + assert_eq!(a + &b, a_extension + b); + } + #[test] + fn mul_degree_2_with_degree_6_extension() { + let a = Fp2E::new([FpE::from(3), FpE::from(4)]); + let a_extension = a.clone().to_extension::(); + let b = Fp6E::from(2); + assert_eq!(a * &b, a_extension * b); + } + #[test] + fn div_degree_6_degree_12_extension() { + let a = Fp6E::from(3); + let a_extension = Fp12E::from(3); + let b = Fp12E::from(2); + assert_eq!(a / &b, a_extension / b); + } + + #[test] + fn double_equals_sum_two_times() { + let a = FpE::from(3); + assert_eq!(a.double(), a.clone() + a); + } + #[test] + fn base_field_sum_is_asociative() { + let a = FpE::from(3); + let b = FpE::from(2); + let c = &a + &b; + assert_eq!(a.double() + b, a + c); + } + #[test] + fn degree_2_extension_mul_is_conmutative() { + let a = Fp2E::from(3); + let b = Fp2E::new([FpE::from(2), FpE::from(4)]); + assert_eq!(&a * &b, b * a); + } + + #[test] + fn base_field_pow_p_is_identity() { + let a = FpE::from(3); + assert_eq!(a.pow(BLS12377_PRIME_FIELD_ORDER), a); + } + #[test] + fn square_equals_mul_two_times() { + let a = FpE::from(3); + assert_eq!(a.square(), a.clone() * a); } } diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/mod.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/mod.rs index 8fc713a88..5fe6ce8bd 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/mod.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/mod.rs @@ -1,2 +1,3 @@ pub mod curve; pub mod field_extension; +pub mod twist; diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/twist.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/twist.rs new file mode 100644 index 000000000..e0aa87c59 --- /dev/null +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/twist.rs @@ -0,0 +1,172 @@ +use super::field_extension::Degree2ExtensionField; +use crate::elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint; +use crate::elliptic_curve::traits::IsEllipticCurve; +use crate::unsigned_integer::element::U384; +use crate::{ + elliptic_curve::short_weierstrass::traits::IsShortWeierstrass, field::element::FieldElement, +}; + +const GENERATOR_X_0: U384 = U384::from_hex_unchecked("0x018480be71c785fec89630a2a3841d01c565f071203e50317ea501f557db6b9b71889f52bb53540274e3e48f7c005196"); +const GENERATOR_X_1: U384 = U384::from_hex_unchecked("0x00ea6040e700403170dc5a51b1b140d5532777ee6651cecbe7223ece0799c9de5cf89984bff76fe6b26bfefa6ea16afe"); +const GENERATOR_Y_0: U384 = U384::from_hex_unchecked("0x00690d665d446f7bd960736bcbb2efb4de03ed7274b49a58e458c282f832d204f2cf88886d8c7c2ef094094409fd4ddf"); +const GENERATOR_Y_1: U384 = U384::from_hex_unchecked("0x00f8169fd28355189e549da3151a70aa61ef11ac3d591bf12463b01acee304c24279b83f5e52270bd9a1cdd185eb8f93"); + +/// The description of the curve. +#[derive(Clone, Debug)] +pub struct BLS12377TwistCurve; + +impl IsEllipticCurve for BLS12377TwistCurve { + type BaseField = Degree2ExtensionField; + type PointRepresentation = ShortWeierstrassProjectivePoint; + + fn generator() -> Self::PointRepresentation { + Self::PointRepresentation::new([ + FieldElement::new([ + FieldElement::new(GENERATOR_X_0), + FieldElement::new(GENERATOR_X_1), + ]), + FieldElement::new([ + FieldElement::new(GENERATOR_Y_0), + FieldElement::new(GENERATOR_Y_1), + ]), + FieldElement::one(), + ]) + } +} + +impl IsShortWeierstrass for BLS12377TwistCurve { + fn a() -> FieldElement { + FieldElement::zero() + } + + fn b() -> FieldElement { + FieldElement::new([FieldElement::zero(), + FieldElement::from_hex_unchecked("0x10222f6db0fd6f343bd03737460c589dc7b4f91cd5fd889129207b63c6bf8000dd39e5c1ccccccd1c9ed9999999999a")]) + } +} + +#[cfg(test)] +mod tests { + use crate::{ + cyclic_group::IsGroup, + elliptic_curve::{ + short_weierstrass::{ + curves::bls12_377::field_extension::{BLS12377PrimeField, Degree2ExtensionField}, + traits::IsShortWeierstrass, + }, + traits::IsEllipticCurve, + }, + field::element::FieldElement, + unsigned_integer::element::U384, + }; + + use super::BLS12377TwistCurve; + type Level0FE = FieldElement; + type Level1FE = FieldElement; + + #[test] + fn create_generator() { + let g = BLS12377TwistCurve::generator(); + let [x, y, _] = g.coordinates(); + assert_eq!( + BLS12377TwistCurve::defining_equation(x, y), + Level1FE::zero() + ); + } + #[test] + // Values checked in sage + fn add_point_three_times_equals_operate_with_self_3() { + let px = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x11a87eda97b96e733c2eb833ae35531b87878b416d57b370c7cd13b5f3c413387633b0ca6dfead19305318501376087")), + Level0FE::new(U384::from_hex_unchecked("0xa4a6d842722f2636937acf0e889ab343e121a599b8a3a9bd3be766da7d84f8e060be00f06bb2d29df963bf2d847598")) + ]); + let py = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x75589c0925d6cf45e715460ea7cb3388d4e21d9b79aa8411567d8de85ba5561bcab80a5c0b363e31817d458e5b2a2a")), + Level0FE::new(U384::from_hex_unchecked("0xcb4e1e4b160cc6c92e7b3dd0b2f4053bc7178d201e7788796a6035c59ccd586635796e97003b1f76eca273576f01ac")) + ]); + + let expectedx = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x1aba32e70b88834d0cd5fb3a27eda8211eb94b6a191cd287f798145c09dc64dabda377836c31d31cc728635425ccc61")), + Level0FE::new(U384::from_hex_unchecked("0x146b578a9c3d92f64baafa082d27c3446fb197659bbd4ac45e290f5f49ae308599448dc288140a4049bac3c6e3e1aac")) + ]); + let expectedy = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x1417486a114a5a9074151a3a2c710dc105cce81de69a91067758355cda7049a2ad8077a2343679bba473484ad0cddd6")), + Level0FE::new(U384::from_hex_unchecked("0x195c939995782a07b26e3b44b49d58eb0951d452d0e8928f218a8e63f74f74860cb56265e437da80df67b6254b27cd")) + ]); + let p = BLS12377TwistCurve::create_point_from_affine(px, py).unwrap(); + let expected = BLS12377TwistCurve::create_point_from_affine(expectedx, expectedy).unwrap(); + assert_eq!(p.operate_with_self(3_u16), expected); + } + + #[test] + // Values checked in sage + fn operate_with_self_test() { + let px = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x2233db786c8cb6a3b6846aebad4ce3f5346961c8bade4c129d920170d1ceeb02d84fd4e12b592f0cba64e083d75167")), + Level0FE::new(U384::from_hex_unchecked("0x12d1c7ac03cb1991993cdb9d38c50588b67c18ed9b9db5f84ac5b59c201f6493a42f690169b96b7a9f12fae4718b6cb")) + ]); + + let py = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x160cc59bb3929b1073996aa370c880e002b81f3e4f7275636caf55754bbfcfe1d43c5d91ee7f3cb49254be2366d5d0")), + Level0FE::new(U384::from_hex_unchecked("0xe66460970bf2fc79831983744d7c83fad910266fd56f08b4a8f737e7609d88930503091e06228a184627b57c02352")) + ]); + + let qx = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x1124128cf7166bb67207327079f8a3e75d876e3b6dd54cc05c766951c5d832aa202c57ed2308d78283e4c859be8fee3")), + Level0FE::new(U384::from_hex_unchecked("0x1889e19d4f67d120d367c15f7bc23529fe4e335627e0eb16ec2bafe6199f0e7d393c5413fc7157ec03d5d56e1eb333")) + ]); + + let qy = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x16db05c371bf6f28e92faa77d3abf5c66c4feea84d334807f46ee69227a2144a827b00f8bcf4179b97922a85ebd5776")), + Level0FE::new(U384::from_hex_unchecked("0x105def68752ac5cb73f3b692b3c877f2febe6cd8a679584f4b1c64f9886f12b15dd7909251bc1e90d559fadd6b1f8f5")) + ]); + + let scalar = U384::from_hex_unchecked( + "0x3061aa3679b1865fa09dac7339a87511147f015aa8997fae59b475d751bc16f", + ); + + let p = BLS12377TwistCurve::create_point_from_affine(px, py).unwrap(); + let q = BLS12377TwistCurve::create_point_from_affine(qx, qy).unwrap(); + + assert_eq!(p.operate_with_self(scalar), q); + } + + #[test] + // Values checked in sage + fn add_two_points() { + let px = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x11a87eda97b96e733c2eb833ae35531b87878b416d57b370c7cd13b5f3c413387633b0ca6dfead19305318501376087")), + Level0FE::new(U384::from_hex_unchecked("0xa4a6d842722f2636937acf0e889ab343e121a599b8a3a9bd3be766da7d84f8e060be00f06bb2d29df963bf2d847598")) + ]); + + let py = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x75589c0925d6cf45e715460ea7cb3388d4e21d9b79aa8411567d8de85ba5561bcab80a5c0b363e31817d458e5b2a2a")), + Level0FE::new(U384::from_hex_unchecked("0xcb4e1e4b160cc6c92e7b3dd0b2f4053bc7178d201e7788796a6035c59ccd586635796e97003b1f76eca273576f01ac")) + ]); + + let qx = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0xa27279ea48d8e812223956c84ae89c5de09e67c7052c056d936da4578dcf0b30799f2212af0017fe50e146c5c2ce05")), + Level0FE::new(U384::from_hex_unchecked("0xaed1579f3de386644e0ffac471e98f8f1d97a6be4d88a0c516bc9fd4d7780649424c3d51bb85d074d66560e2c2bb07")) + ]); + + let qy = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x6e7e249e0d7c81d0fec62a3f96d6fefd7d6c87019559b03664a015a2ed536d98e6432b93ec219426f9729f119c7982")), + Level0FE::new(U384::from_hex_unchecked("0x104c4e4adb48273511a0473d742724f48042b967591ab9b86731bb902debfd44d89571af704340614f6618863fc5841")) + ]); + + let expectedx = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x19d74f8769a27aae05c5b50b2d051849f6feab554d0fd4f51c7fe43d918fac1d966c97dd6e61b2f7fc13694495dc259")), + Level0FE::new(U384::from_hex_unchecked("0x11f4194886ad75e3baff9853734e9ef4fe5f20d333951ba126bca7dd54ebc4998b17d4d315d29147dc22124c5464a64")) + ]); + let expectedy = Level1FE::new([ + Level0FE::new(U384::from_hex_unchecked("0x14faa941c0cdf5567c294bc9e73e83c4602f331a7400222c8475fba4c6a688b12ce8f7cc20e54eaac1af6046aec58bd")), + Level0FE::new(U384::from_hex_unchecked("0x7cee0c4760e2bf76047cda31141e6242c5893ba5c2fba5f23c0048545912e309dc647f4cfe2db17b23aa2f57c3d8c3")) + ]); + + let p = BLS12377TwistCurve::create_point_from_affine(px, py).unwrap(); + let q = BLS12377TwistCurve::create_point_from_affine(qx, qy).unwrap(); + let expected = BLS12377TwistCurve::create_point_from_affine(expectedx, expectedy).unwrap(); + + assert_eq!(p.operate_with(&q), expected); + } +} diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/compression.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/compression.rs index 18f30299f..548f2e986 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/compression.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/compression.rs @@ -18,6 +18,11 @@ type G1Point = ShortWeierstrassProjectivePoint; type G2Point = ShortWeierstrassProjectivePoint; type BLS12381FieldElement = FieldElement; +/// This functionality includes the compression and decompression for points belonging to the BLS12-381, following the ideas in +/// Zcash curve compression, check https://hackmd.io/@benjaminion/bls12-381#Point-compression and https://github.com/zcash/librustzcash/blob/6e0364cd42a2b3d2b958a54771ef51a8db79dd29/pairing/src/bls12_381/README.md#serialization +/// The way we encode points differs from the one used ordinarily for serialization in lambdaworks. +/// G1 points are represented by their x coordinate in big-endian form (48 bytes), with the three most significant bits used to give information on the compressed format, whether the point is the point at infinity and which of the two roots to take +/// G2 points are represented by their x coordinate in big-endian form (96 bytes), following the order a * i + b. The three most significant bits contain the same type of information as in G1. impl Compress for BLS12381Curve { type G1Point = G1Point; @@ -75,6 +80,7 @@ impl Compress for BLS12381Curve { if second_bit == 1 { return Ok(G1Point::neutral_element()); } + // We obtain the third bit let third_bit = prefix_bits & 1_u8; let first_byte_without_control_bits = (first_byte << 3) >> 3; diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/curve.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/curve.rs index ece973a4f..a080aa77b 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/curve.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/curve.rs @@ -13,6 +13,8 @@ use crate::{ pub const SUBGROUP_ORDER: U256 = U256::from_hex_unchecked("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); +pub const CURVE_COFACTOR: U256 = U256::from_hex_unchecked("0x396c8c005555e1568c00aaab0000aaab"); + pub type BLS12381FieldElement = FieldElement; pub type BLS12381TwistCurveFieldElement = FieldElement; diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs index ecf87e2d9..cb41e5aeb 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs @@ -21,6 +21,7 @@ impl IsModulus for BLS12381FieldModulus { } pub type BLS12381PrimeField = MontgomeryBackendPrimeField; +type Fp2E = FieldElement; ////////////////// #[derive(Clone, Debug)] @@ -199,6 +200,16 @@ impl HasCubicNonResidue for LevelTwoResidue { } } +impl HasQuadraticNonResidue for LevelTwoResidue { + fn residue() -> FieldElement { + FieldElement::new([ + FieldElement::new(U384::from("1")), + FieldElement::new(U384::from("1")), + ]) + } +} +pub type Degree4ExtensionField = QuadraticExtensionField; + pub type Degree6ExtensionField = CubicExtensionField; #[derive(Debug, Clone)] @@ -284,6 +295,14 @@ impl FieldElement { } } +/// Computes the multiplication of an element of fp2 by the level two non-residue 9+u. +pub fn mul_fp2_by_nonresidue(a: &Fp2E) -> Fp2E { + // (c0 + c1 * u) * (1 + u) = (c0 - c1) + (c1 + c0) * u + let c0 = &a.value()[0] - &a.value()[1]; // c0 - c1 + let c1 = &a.value()[0] + &a.value()[1]; // c1 + c0 + + Fp2E::new([c0, c1]) +} #[cfg(test)] mod tests { use crate::elliptic_curve::{ diff --git a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/pairing.rs b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/pairing.rs index b0c0c6cd2..8107f69ec 100644 --- a/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/pairing.rs +++ b/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/pairing.rs @@ -1,11 +1,12 @@ -use super::curve::MILLER_LOOP_CONSTANT; use super::{ curve::BLS12381Curve, - field_extension::{BLS12381PrimeField, Degree12ExtensionField, Degree2ExtensionField}, + field_extension::{ + mul_fp2_by_nonresidue, BLS12381PrimeField, Degree12ExtensionField, Degree2ExtensionField, + Degree4ExtensionField, + }, twist::BLS12381TwistCurve, }; use crate::{cyclic_group::IsGroup, elliptic_curve::traits::IsPairing, errors::PairingError}; - use crate::{ elliptic_curve::short_weierstrass::{ curves::bls12_381::field_extension::{Degree6ExtensionField, LevelTwoResidue}, @@ -13,11 +14,76 @@ use crate::{ traits::IsShortWeierstrass, }, field::{element::FieldElement, extensions::cubic::HasCubicNonResidue}, - unsigned_integer::element::{UnsignedInteger, U256}, + unsigned_integer::element::U256, }; +type FpE = FieldElement; +type Fp2E = FieldElement; +type Fp4E = FieldElement; +type Fp6E = FieldElement; +type Fp12E = FieldElement; + pub const SUBGROUP_ORDER: U256 = U256::from_hex_unchecked("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); +// value of x in binary + +// We use |x|, then if needed we apply the minus sign in the final exponentiation by applying the inverse (in this case the conjugate because the element is in the cyclotomic subgroup) +pub const X: u64 = 0xd201000000010000; + +// X = 1101001000000001000000000000000000000000000000010000000000000000 +pub const X_BINARY: &[bool] = &[ + true, true, false, true, false, false, true, false, false, false, false, false, false, false, + false, true, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, true, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, +]; + +// GAMMA constants used to compute the Frobenius morphisms +/// We took these constants from https://github.com/hecmas/zkNotebook/blob/main/src/BLS12381/constants.ts + +pub const GAMMA_11: Fp2E = Fp2E::const_from_raw([ + FpE::from_hex_unchecked("1904D3BF02BB0667C231BEB4202C0D1F0FD603FD3CBD5F4F7B2443D784BAB9C4F67EA53D63E7813D8D0775ED92235FB8"), + FpE::from_hex_unchecked("FC3E2B36C4E03288E9E902231F9FB854A14787B6C7B36FEC0C8EC971F63C5F282D5AC14D6C7EC22CF78A126DDC4AF3"), +]); + +pub const GAMMA_12: Fp2E = Fp2E::const_from_raw([ + FpE::from_hex_unchecked("0"), + FpE::from_hex_unchecked("1A0111EA397FE699EC02408663D4DE85AA0D857D89759AD4897D29650FB85F9B409427EB4F49FFFD8BFD00000000AAAC"), +]); + +pub const GAMMA_13: Fp2E = Fp2E::const_from_raw([ + FpE::from_hex_unchecked("6AF0E0437FF400B6831E36D6BD17FFE48395DABC2D3435E77F76E17009241C5EE67992F72EC05F4C81084FBEDE3CC09"), + FpE::from_hex_unchecked("6AF0E0437FF400B6831E36D6BD17FFE48395DABC2D3435E77F76E17009241C5EE67992F72EC05F4C81084FBEDE3CC09"), +]); + +pub const GAMMA_14: Fp2E = Fp2E::const_from_raw([ + FpE::from_hex_unchecked("1A0111EA397FE699EC02408663D4DE85AA0D857D89759AD4897D29650FB85F9B409427EB4F49FFFD8BFD00000000AAAD"), + FpE::from_hex_unchecked("0"), +]); + +pub const GAMMA_15: Fp2E = Fp2E::const_from_raw([ + FpE::from_hex_unchecked("5B2CFD9013A5FD8DF47FA6B48B1E045F39816240C0B8FEE8BEADF4D8E9C0566C63A3E6E257F87329B18FAE980078116"), + FpE::from_hex_unchecked("144E4211384586C16BD3AD4AFA99CC9170DF3560E77982D0DB45F3536814F0BD5871C1908BD478CD1EE605167FF82995"), +]); + +/// GAMMA_2i = GAMMA_1i * GAMMA_1i.conjugate() +pub const GAMMA_21: FpE = FpE::from_hex_unchecked( + "5F19672FDF76CE51BA69C6076A0F77EADDB3A93BE6F89688DE17D813620A00022E01FFFFFFFEFFFF", +); + +pub const GAMMA_22: FpE = FpE::from_hex_unchecked( + "5F19672FDF76CE51BA69C6076A0F77EADDB3A93BE6F89688DE17D813620A00022E01FFFFFFFEFFFE", +); + +pub const GAMMA_23: FpE = + FpE::from_hex_unchecked("1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAA"); + +pub const GAMMA_24: FpE = + FpE::from_hex_unchecked("1A0111EA397FE699EC02408663D4DE85AA0D857D89759AD4897D29650FB85F9B409427EB4F49FFFD8BFD00000000AAAC"); + +pub const GAMMA_25: FpE = + FpE::from_hex_unchecked("1A0111EA397FE699EC02408663D4DE85AA0D857D89759AD4897D29650FB85F9B409427EB4F49FFFD8BFD00000000AAAD"); #[derive(Clone)] pub struct BLS12381AtePairing; @@ -46,6 +112,26 @@ impl IsPairing for BLS12381AtePairing { } } +/// Implements the miller loop for the ate pairing of the BLS12 381 curve. +/// Based on algorithm 9.2, page 212 of the book +/// "Topics in computational number theory" by W. Bons and K. Lenstra +#[allow(unused)] +pub fn miller( + q: &ShortWeierstrassProjectivePoint, + p: &ShortWeierstrassProjectivePoint, +) -> FieldElement { + let mut r = q.clone(); + let mut f = FieldElement::::one(); + X_BINARY.iter().skip(1).for_each(|bit| { + double_accumulate_line(&mut r, p, &mut f); + if *bit { + add_accumulate_line(&mut r, q, p, &mut f); + } + }); + + f.conjugate() +} + fn double_accumulate_line( t: &mut ShortWeierstrassProjectivePoint, p: &ShortWeierstrassProjectivePoint, @@ -152,69 +238,148 @@ fn add_accumulate_line( ]), ]); } -/// Implements the miller loop for the ate pairing of the BLS12 381 curve. -/// Based on algorithm 9.2, page 212 of the book -/// "Topics in computational number theory" by W. Bons and K. Lenstra -#[allow(unused)] -fn miller( - q: &ShortWeierstrassProjectivePoint, - p: &ShortWeierstrassProjectivePoint, -) -> FieldElement { - let mut r = q.clone(); - let mut f = FieldElement::::one(); - let mut miller_loop_constant = MILLER_LOOP_CONSTANT; - let mut miller_loop_constant_bits: alloc::vec::Vec = alloc::vec![]; - while miller_loop_constant > 0 { - miller_loop_constant_bits.insert(0, (miller_loop_constant & 1) == 1); - miller_loop_constant >>= 1; - } +// To understand more about how to reduce the final exponentiation +// read "Efficient Final Exponentiation via Cyclotomic Structure for +// Pairings over Families of Elliptic Curves" (https://eprint.iacr.org/2020/875.pdf) +// Hard part from https://eprint.iacr.org/2020/875.pdf p14 +// Same implementation as in Constantine https://github.com/mratsim/constantine/blob/master/constantine/math/pairings/pairings_bls12.nim +pub fn final_exponentiation(f: &Fp12E) -> Fp12E { + let f_easy_aux = f.conjugate() * f.inv().unwrap(); + let mut f_easy = frobenius_square(&f_easy_aux) * &f_easy_aux; + + let mut v2 = cyclotomic_square(&f_easy); // v2 = fΒ² + let mut v0 = cyclotomic_pow_x(&f_easy).conjugate(); // v0 = f^x + let mut v1 = f_easy.conjugate(); // v1 = f^-1 + + // (xβˆ’1)Β² + v0 *= v1; // v0 = f^(x-1) + v1 = cyclotomic_pow_x(&v0).conjugate(); // v1 = (f^(x-1))^(x) + + v0 = v0.conjugate(); // v0 = (f^(x-1))^(-1) + v0 *= &v1; // v0 = (f^(x-1))^(-1) * (f^(x-1))^x = (f^(x-1))^(x-1) = f^((x-1)Β²) + + // (x+p) + v1 = cyclotomic_pow_x(&v0).conjugate(); // v1 = f^((x-1)Β².x) + v0 = frobenius(&v0); // f^((x-1)Β².p) + v0 *= &v1; // f^((x-1)Β².p + (x-1)Β².x) = f^((x-1)Β².(x+p)) + + // + 3 + f_easy *= v2; // f^3 + + // (xΒ²+pΒ²βˆ’1) + v2 = cyclotomic_pow_x(&v0).conjugate(); + v1 = cyclotomic_pow_x(&v2).conjugate(); // v1 = f^((x-1)Β².(x+p).xΒ²) + v2 = frobenius_square(&v0); // v2 = f^((x-1)Β².(x+p).pΒ²) + v0 = v0.conjugate(); // v0 = f^((x-1)Β².(x+p).-1) + v0 *= &v1; // v0 = f^((x-1)Β².(x+p).(xΒ²-1)) + v0 *= &v2; // v0 = f^((x-1)Β².(x+p).(xΒ²+pΒ²-1)) + + f_easy *= &v0; + f_easy +} - for bit in miller_loop_constant_bits[1..].iter() { - double_accumulate_line(&mut r, p, &mut f); - if *bit { - add_accumulate_line(&mut r, q, p, &mut f); - } - } - f.inv().unwrap() +////////////////// FROBENIUS MORPHISIMS ////////////////// +pub fn frobenius(f: &Fp12E) -> Fp12E { + let [a, b] = f.value(); // f = a + bw, where a and b in Fp6. + let [a0, a1, a2] = a.value(); // a = a0 + a1 * v + a2 * v^2, where a0, a1 and a2 in Fp2. + let [b0, b1, b2] = b.value(); // b = b0 + b1 * v + b2 * v^2, where b0, b1 and b2 in Fp2. + + // c1 = a0.conjugate() + a1.conjugate() * GAMMA_12 * v + a2.conjugate() * GAMMA_14 * v^2 + let c1 = Fp6E::new([ + a0.conjugate(), + a1.conjugate() * GAMMA_12, + a2.conjugate() * GAMMA_14, + ]); + + let c2 = Fp6E::new([ + b0.conjugate() * GAMMA_11, + b1.conjugate() * GAMMA_13, + b2.conjugate() * GAMMA_15, + ]); + + Fp12E::new([c1, c2]) //c1 + c2 * w } -/// Auxiliary function for the final exponentiation of the ate pairing. fn frobenius_square( f: &FieldElement, ) -> FieldElement { let [a, b] = f.value(); - let w_raised_to_p_squared_minus_one = FieldElement::::new_base("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad"); - let omega_3 = FieldElement::::new_base("1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac"); - let omega_3_squared = FieldElement::::new_base( - "5f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe", - ); - let [a0, a1, a2] = a.value(); let [b0, b1, b2] = b.value(); - let f0 = FieldElement::new([a0.clone(), a1 * &omega_3, a2 * &omega_3_squared]); - let f1 = FieldElement::new([b0.clone(), b1 * omega_3, b2 * omega_3_squared]); + let c1 = Fp6E::new([a0.clone(), GAMMA_22 * a1, GAMMA_24 * a2]); + let c2 = Fp6E::new([GAMMA_21 * b0, GAMMA_23 * b1, GAMMA_25 * b2]); - FieldElement::new([f0, w_raised_to_p_squared_minus_one * f1]) + Fp12E::new([c1, c2]) } -// To understand more about how to reduce the final exponentiation -// read "Efficient Final Exponentiation via Cyclotomic Structure for -// Pairings over Families of Elliptic Curves" (https://eprint.iacr.org/2020/875.pdf) -// -// TODO: implement optimizations for the hard part of the final exponentiation. -#[allow(unused)] -fn final_exponentiation( - base: &FieldElement, -) -> FieldElement { - const PHI_DIVIDED_BY_R: UnsignedInteger<20> = UnsignedInteger::from_hex_unchecked("f686b3d807d01c0bd38c3195c899ed3cde88eeb996ca394506632528d6a9a2f230063cf081517f68f7764c28b6f8ae5a72bce8d63cb9f827eca0ba621315b2076995003fc77a17988f8761bdc51dc2378b9039096d1b767f17fcbde783765915c97f36c6f18212ed0b283ed237db421d160aeb6a1e79983774940996754c8c71a2629b0dea236905ce937335d5b68fa9912aae208ccf1e516c3f438e3ba79"); - - let f1 = base.conjugate() * base.inv().unwrap(); - let f2 = frobenius_square(&f1) * f1; - f2.pow(PHI_DIVIDED_BY_R) +////////////////// CYCLOTOMIC SUBGROUP OPERATIONS ////////////////// +/// Since the result of the Easy Part of the Final Exponentiation belongs to the cyclotomic +/// subgroup of Fp12, we can optimize the square and pow operations used in the Hard Part. + +/// Computes the square of an element of a cyclotomic subgroup of Fp12. +/// Algorithm from Constantine's cyclotomic_square_quad_over_cube +/// https://github.com/mratsim/constantine/blob/master/constantine/math/pairings/cyclotomic_subgroups.nim#L354 +pub fn cyclotomic_square(a: &Fp12E) -> Fp12E { + // a = g + h * w + let [g, h] = a.value(); + let [b0, b1, b2] = g.value(); + let [b3, b4, b5] = h.value(); + + let v0 = Fp4E::new([b0.clone(), b4.clone()]).square(); + let v1 = Fp4E::new([b3.clone(), b2.clone()]).square(); + let v2 = Fp4E::new([b1.clone(), b5.clone()]).square(); + + // r = r0 + r1 * w + // r0 = r00 + r01 * v + r02 * v^2 + // r1 = r10 + r11 * v + r12 * v^2 + + // r00 = 3v00 - 2b0 + let mut r00 = &v0.value()[0] - b0; + r00 = r00.double(); + r00 += v0.value()[0].clone(); + + // r01 = 3v10 -2b1 + let mut r01 = &v1.value()[0] - b1; + r01 = r01.double(); + r01 += v1.value()[0].clone(); + + // r11 = 3v01 - 2b4 + let mut r11 = &v0.value()[1] + b4; + r11 = r11.double(); + r11 += v0.value()[1].clone(); + + // r12 = 3v11 - 2b5 + let mut r12 = &v1.value()[1] + b5; + r12 = r12.double(); + r12 += v1.value()[1].clone(); + + // 3 * (9 + u) * v21 + 2b3 + let v21 = mul_fp2_by_nonresidue(&v2.value()[1]); + let mut r10 = &v21 + b3; + r10 = r10.double(); + r10 += v21; + + // 3 * (9 + u) * v20 - 2b3 + let mut r02 = &v2.value()[0] - b2; + r02 = r02.double(); + r02 += v2.value()[0].clone(); + + Fp12E::new([Fp6E::new([r00, r01, r02]), Fp6E::new([r10, r11, r12])]) } +#[allow(clippy::needless_range_loop)] +pub fn cyclotomic_pow_x(f: &Fp12E) -> Fp12E { + let mut result = Fp12E::one(); + X_BINARY.iter().for_each(|&bit| { + result = cyclotomic_square(&result); + if bit { + result = &result * f; + } + }); + result +} #[cfg(test)] mod tests { use crate::{ @@ -294,4 +459,58 @@ mod tests { let result = BLS12381AtePairing::compute_batch(&[(&p.to_affine(), &q)]); assert!(result.is_err()) } + #[test] + fn apply_12_times_frobenius_is_identity() { + let f = Fp12E::from_coefficients(&[ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + ]); + let mut result = frobenius(&f); + for _ in 1..12 { + result = frobenius(&result); + } + assert_eq!(f, result) + } + + #[test] + fn apply_6_times_frobenius_square_is_identity() { + let f = Fp12E::from_coefficients(&[ + "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", + ]); + let mut result = frobenius_square(&f); + for _ in 1..6 { + result = frobenius_square(&result); + } + assert_eq!(f, result) + } + + #[test] + fn cyclotomic_square_equals_square() { + let p = BLS12381Curve::generator(); + let q = BLS12381TwistCurve::generator(); + let f = miller(&q, &p); + let f_easy_aux = f.conjugate() * f.inv().unwrap(); // f ^ (p^6 - 1) because f^(p^6) = f.conjugate(). + let f_easy = &frobenius_square(&f_easy_aux) * f_easy_aux; // (f^{p^6 - 1})^(p^2) * (f^{p^6 - 1}). + assert_eq!(cyclotomic_square(&f_easy), f_easy.square()); + } + + #[test] + fn test_double_accumulate_line_doubles_point_correctl_2() { + let g1 = BLS12381Curve::generator(); + let g2 = BLS12381TwistCurve::generator(); + let mut r = g2.clone(); + let mut f = FieldElement::one(); + double_accumulate_line(&mut r, &g1, &mut f); + let expected_r = g2.operate_with(&g2); + assert_eq!(r.to_affine(), expected_r.to_affine()); + } + + #[test] + fn cyclotomic_pow_x_equals_pow() { + let p = BLS12381Curve::generator(); + let q = BLS12381TwistCurve::generator(); + let f = miller(&q, &p); + let f_easy_aux = f.conjugate() * f.inv().unwrap(); // f ^ (p^6 - 1) because f^(p^6) = f.conjugate(). + let f_easy = &frobenius_square(&f_easy_aux) * f_easy_aux; // (f^{p^6 - 1})^(p^2) * (f^{p^6 - 1}). + assert_eq!(cyclotomic_pow_x(&f_easy), f_easy.pow(X)); + } } diff --git a/math/src/elliptic_curve/short_weierstrass/point.rs b/math/src/elliptic_curve/short_weierstrass/point.rs index ec30219b1..679edeaea 100644 --- a/math/src/elliptic_curve/short_weierstrass/point.rs +++ b/math/src/elliptic_curve/short_weierstrass/point.rs @@ -1,7 +1,7 @@ use crate::{ cyclic_group::IsGroup, elliptic_curve::{ - point::ProjectivePoint, + point::{JacobianPoint, ProjectivePoint}, traits::{EllipticCurveError, FromAffine, IsEllipticCurve}, }, errors::DeserializationError, @@ -15,7 +15,6 @@ use super::traits::IsShortWeierstrass; use crate::traits::AsBytes; #[cfg(feature = "alloc")] use alloc::vec::Vec; - #[derive(Clone, Debug)] pub struct ShortWeierstrassProjectivePoint(pub ProjectivePoint); @@ -53,6 +52,9 @@ impl ShortWeierstrassProjectivePoint { } pub fn double(&self) -> Self { + if self.is_neutral_element() { + return self.clone(); + } let [px, py, pz] = self.coordinates(); let px_square = px * px; @@ -85,13 +87,8 @@ impl ShortWeierstrassProjectivePoint { let zp = eight_s_cube; Self::new([xp, yp, zp]) } - + // https://hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/madd-1998-cmo pub fn operate_with_affine(&self, other: &Self) -> Self { - let [px, py, pz] = self.coordinates(); - let [qx, qy, _qz] = other.coordinates(); - let u = qy * pz; - let v = qx * pz; - if self.is_neutral_element() { return other.clone(); } @@ -99,6 +96,11 @@ impl ShortWeierstrassProjectivePoint { return self.clone(); } + let [px, py, pz] = self.coordinates(); + let [qx, qy, _qz] = other.coordinates(); + let u = qy * pz; + let v = qx * pz; + if u == *py { if v != *px || *py == FieldElement::zero() { return Self::new([ @@ -377,11 +379,229 @@ where } } +#[derive(Clone, Debug)] +pub struct ShortWeierstrassJacobianPoint(pub JacobianPoint); + +impl ShortWeierstrassJacobianPoint { + /// Creates an elliptic curve point giving the projective [x: y: z] coordinates. + pub const fn new(value: [FieldElement; 3]) -> Self { + Self(JacobianPoint::new(value)) + } + + /// Returns the `x` coordinate of the point. + pub fn x(&self) -> &FieldElement { + self.0.x() + } + + /// Returns the `y` coordinate of the point. + pub fn y(&self) -> &FieldElement { + self.0.y() + } + + /// Returns the `z` coordinate of the point. + pub fn z(&self) -> &FieldElement { + self.0.z() + } + + /// Returns a tuple [x, y, z] with the coordinates of the point. + pub fn coordinates(&self) -> &[FieldElement; 3] { + self.0.coordinates() + } + + /// Creates the same point in affine coordinates. That is, + /// returns [x / z^2: y / z^3: 1] where `self` is [x: y: z]. + /// Panics if `self` is the point at infinity. + pub fn to_affine(&self) -> Self { + Self(self.0.to_affine()) + } + + pub fn double(&self) -> Self { + if self.is_neutral_element() { + return self.clone(); + } + let [x1, y1, z1] = self.coordinates(); + //http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/doubling/dbl-2009-l + + if E::a() == FieldElement::zero() { + let a = x1.square(); // A = x1^2 + let b = y1.square(); // B = y1^2 + let c = b.square(); // C = B^2 + let x1_plus_b = x1 + &b; // (X1 + B) + let x1_plus_b_square = x1_plus_b.square(); // (X1 + B)^2 + let d = (&x1_plus_b_square - &a - &c).double(); // D = 2 * ((X1 + B)^2 - A - C) + let e = &a.double() + &a; // E = 3 * A + let f = e.square(); // F = E^2 + let x3 = &f - &d.double(); // X3 = F - 2 * D + let y3 = &e * (&d - &x3) - &c.double().double().double(); // Y3 = E * (D - X3) - 8 * C + let z3 = (y1 * z1).double(); // Z3 = 2 * Y1 * Z1 + + Self::new([x3, y3, z3]) + } else { + // http://www.hyperelliptic.org/EFD/g1p/data/shortw/jacobian-0/doubling/dbl-2009-alnr + // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l + let xx = x1.square(); // XX = X1^2 + let yy = y1.square(); // YY = Y1^2 + let yyyy = yy.square(); // YYYY = YY^2 + let zz = z1.square(); // ZZ = Z1^2 + let s = ((x1 + &yy).square() - &xx - &yyyy).double(); // S = 2 * ((X1 + YY)^2 - XX - YYYY) + let m = &xx.double() + &xx + &E::a() * &zz.square(); // M = 3 * XX + a * ZZ^2 + let x3 = m.square() - &s.double(); // X3 = M^2 - 2 * S + let y3 = m * (&s - &x3) - &yyyy.double().double().double(); // Y3 = M * (S - X3) - 8 * YYYY + let z3 = (y1 + z1).square() - &yy - &zz; // Z3 = (Y1 + Z1)^2 - YY - ZZ + + Self::new([x3, y3, z3]) + } + } + + pub fn operate_with_affine(&self, other: &Self) -> Self { + let [x1, y1, z1] = self.coordinates(); + let [x2, y2, _z2] = other.coordinates(); + + if self.is_neutral_element() { + return other.clone(); + } + if other.is_neutral_element() { + return self.clone(); + } + + let z1z1 = z1.square(); + let u1 = x1; + let u2 = x2 * &z1z1; + let s1 = y1; + let s2 = y2 * z1 * &z1z1; + + if *u1 == u2 { + if *s1 == s2 { + self.double() // Is the same point + } else { + Self::neutral_element() // P + (-P) = 0 + } + } else { + let h = &u2 - u1; + let hh = h.square(); + let hhh = &h * &hh; + let r = &s2 - s1; + let v = u1 * &hh; + let x3 = r.square() - (&hhh + &v + &v); + let y3 = r * (&v - &x3) - s1 * &hhh; + let z3 = z1 * &h; + + Self::new([x3, y3, z3]) + } + } +} + +impl PartialEq for ShortWeierstrassJacobianPoint { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } +} + +impl Eq for ShortWeierstrassJacobianPoint {} + +impl FromAffine for ShortWeierstrassJacobianPoint { + fn from_affine( + x: FieldElement, + y: FieldElement, + ) -> Result { + if E::defining_equation(&x, &y) != FieldElement::zero() { + Err(EllipticCurveError::InvalidPoint) + } else { + let coordinates = [x, y, FieldElement::one()]; + Ok(ShortWeierstrassJacobianPoint::new(coordinates)) + } + } +} + +impl IsGroup for ShortWeierstrassJacobianPoint { + /// The point at infinity. + fn neutral_element() -> Self { + Self::new([ + FieldElement::one(), + FieldElement::one(), + FieldElement::zero(), + ]) + } + + fn is_neutral_element(&self) -> bool { + let pz = self.z(); + pz == &FieldElement::zero() + } + + /// Computes the addition of `self` and `other`. + /// https://github.com/mratsim/constantine/blob/65147ed815d96fa94a05d307c1d9980877b7d0e8/constantine/math/elliptic/ec_shortweierstrass_jacobian.md + fn operate_with(&self, other: &Self) -> Self { + if self.is_neutral_element() { + return other.clone(); + } + + if other.is_neutral_element() { + return self.clone(); + } + + let [x1, y1, z1] = self.coordinates(); + let [x2, y2, z2] = other.coordinates(); + + let z1_sq = z1.square(); // Z1^2 + let z2_sq = z2.square(); // Z2^2 + + let u1 = x1 * &z2_sq; // U1 = X1 * Z2^2 + let u2 = x2 * &z1_sq; // U2 = X2 * Z1^2 + + let z1_cu = z1 * &z1_sq; // Z1^3 + let z2_cu = z2 * &z2_sq; // Z2^3 + + let s1 = y1 * &z2_cu; // S1 = Y1 * Z2^3 + let s2 = y2 * &z1_cu; // S2 = Y2 * Z1^3 + + if u1 == u2 { + if s1 == s2 { + return self.double(); // P + P = 2P + } else { + return Self::neutral_element(); // P + (-P) = 0 + } + } + // H = U2 - U1 + let h = u2 - &u1; + // I = (2 * H)^2 + let i = h.double().square(); + // J = H * I + let j = -(&h * &i); + + // R = 2 * (S2 - S1) + let r = (s2 - &s1).double(); + + // V = U1 * I + let v = u1 * &i; + + // X3 = R^2 + J - 2 * V + let x3 = r.square() + &j - v.double(); + + // Y3 = R * (V - X3) + 2 * S1 * J + let y3 = r * (v - &x3) + (s1 * &j.double()); + + // Z3 = 2 * Z1 * Z2 * H + let z3 = z1 * z2; + let z3 = z3.double() * h; + + Self::new([x3, y3, z3]) + } + + /// Returns the additive inverse of the jacobian point `p` + fn neg(&self) -> Self { + let [x, y, z] = self.coordinates(); + Self::new([x.clone(), -y, z.clone()]) + } +} + #[cfg(test)] mod tests { use super::*; use crate::elliptic_curve::short_weierstrass::curves::bls12_381::curve::BLS12381Curve; + use crate::elliptic_curve::short_weierstrass::curves::bls12_381::curve::{ + CURVE_COFACTOR, SUBGROUP_ORDER, + }; #[cfg(feature = "alloc")] use crate::{ elliptic_curve::short_weierstrass::curves::bls12_381::field_extension::BLS12381PrimeField, @@ -399,6 +619,28 @@ mod tests { BLS12381Curve::create_point_from_affine(x, y).unwrap() } + #[cfg(feature = "alloc")] + #[test] + fn operate_with_works_jacobian() { + let x = FEE::new_base("36bb494facde72d0da5c770c4b16d9b2d45cfdc27604a25a1a80b020798e5b0dbd4c6d939a8f8820f042a29ce552ee5"); + let y = FEE::new_base("7acf6e49cc000ff53b06ee1d27056734019c0a1edfa16684da41ebb0c56750f73bc1b0eae4c6c241808a5e485af0ba0"); + let p = ShortWeierstrassJacobianPoint::::from_affine(x, y).unwrap(); + + assert_eq!(p.operate_with(&p), p.double()); + } + + #[cfg(feature = "alloc")] + #[test] + fn operate_with_self_works_jacobian() { + let x = FEE::new_base("36bb494facde72d0da5c770c4b16d9b2d45cfdc27604a25a1a80b020798e5b0dbd4c6d939a8f8820f042a29ce552ee5"); + let y = FEE::new_base("7acf6e49cc000ff53b06ee1d27056734019c0a1edfa16684da41ebb0c56750f73bc1b0eae4c6c241808a5e485af0ba0"); + let p = ShortWeierstrassJacobianPoint::::from_affine(x, y).unwrap(); + + assert_eq!( + p.operate_with_self(5_u16), + p.double().double().operate_with(&p) + ); + } #[cfg(feature = "alloc")] #[test] fn byte_conversion_from_and_to_be_projective() { @@ -586,4 +828,63 @@ mod tests { DeserializationError::InvalidAmountOfBytes ); } + + #[test] + fn test_jacobian_vs_projective_operation() { + let x = FEE::new_base("36bb494facde72d0da5c770c4b16d9b2d45cfdc27604a25a1a80b020798e5b0dbd4c6d939a8f8820f042a29ce552ee5"); + let y = FEE::new_base("7acf6e49cc000ff53b06ee1d27056734019c0a1edfa16684da41ebb0c56750f73bc1b0eae4c6c241808a5e485af0ba0"); + + let p = ShortWeierstrassJacobianPoint::::from_affine(x.clone(), y.clone()) + .unwrap(); + let q = ShortWeierstrassProjectivePoint::::from_affine(x, y).unwrap(); + + let sum_jacobian = p.operate_with_self(7_u16); + let sum_projective = q.operate_with_self(7_u16); + + // Convert the result to affine coordinates + let sum_jacobian_affine = sum_jacobian.to_affine(); + let [x_j, y_j, _] = sum_jacobian_affine.coordinates(); + + // Convert the result to affine coordinates + let binding = sum_projective.to_affine(); + let [x_p, y_p, _] = binding.coordinates(); + + assert_eq!(x_j, x_p, "x coordintates do not match"); + assert_eq!(y_j, y_p, "y coordinates do not match"); + } + + #[test] + fn test_multiplication_by_order_projective() { + let x = FEE::new_base("36bb494facde72d0da5c770c4b16d9b2d45cfdc27604a25a1a80b020798e5b0dbd4c6d939a8f8820f042a29ce552ee5"); + let y = FEE::new_base("7acf6e49cc000ff53b06ee1d27056734019c0a1edfa16684da41ebb0c56750f73bc1b0eae4c6c241808a5e485af0ba0"); + + let p = ShortWeierstrassProjectivePoint::::from_affine(x.clone(), y.clone()) + .unwrap(); + + let g = p + .operate_with_self(SUBGROUP_ORDER) + .operate_with_self(CURVE_COFACTOR); + + assert!( + g.is_neutral_element(), + "Multiplication by order should result in the neutral element" + ); + } + + #[test] + fn test_multiplication_by_order_jacobian() { + let x = FEE::new_base("36bb494facde72d0da5c770c4b16d9b2d45cfdc27604a25a1a80b020798e5b0dbd4c6d939a8f8820f042a29ce552ee5"); + let y = FEE::new_base("7acf6e49cc000ff53b06ee1d27056734019c0a1edfa16684da41ebb0c56750f73bc1b0eae4c6c241808a5e485af0ba0"); + + let p = ShortWeierstrassJacobianPoint::::from_affine(x.clone(), y.clone()) + .unwrap(); + let g = p + .operate_with_self(SUBGROUP_ORDER) + .operate_with_self(CURVE_COFACTOR); + + assert!( + g.is_neutral_element(), + "Multiplication by order should result in the neutral element" + ); + } } diff --git a/math/src/elliptic_curve/short_weierstrass/traits.rs b/math/src/elliptic_curve/short_weierstrass/traits.rs index b86261dfa..be456a3bd 100644 --- a/math/src/elliptic_curve/short_weierstrass/traits.rs +++ b/math/src/elliptic_curve/short_weierstrass/traits.rs @@ -16,7 +16,7 @@ pub trait IsShortWeierstrass: IsEllipticCurve + Clone + Debug { x: &FieldElement, y: &FieldElement, ) -> FieldElement { - y.pow(2_u16) - x.pow(3_u16) - Self::a() * x - Self::b() + y.square() - ((x.square() + Self::a()) * x + Self::b()) } } diff --git a/math/src/field/README.md b/math/src/field/README.md index c19b302aa..0bad353cb 100644 --- a/math/src/field/README.md +++ b/math/src/field/README.md @@ -8,10 +8,10 @@ This folder contains the different field backends, including field extensions. T - [Goldilocks-448](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/field/fields/p448_goldilocks_prime_field.rs) - [Mersenne-31](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/field/fields/mersenne31/field.rs): $2^{31} - 1$ and its [quadratic extension](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/field/fields/mersenne31/extension.rs) - [Baby Bear](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/field/fields/fft_friendly/babybear.rs) and its [quadratic extension](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/field/fields/fft_friendly/quadratic_babybear.rs): FFT-friendly, $2^{31} - 2^{27} + 1$. -- [Scalar field of BN-254](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bn_254/default_types.rs) -- [Base field of BN-254](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bn_254/field_extension.rs) and its quadratic extension, quartic, sextic and twelth degree extensions. -- [Scalar field of BLS12-381](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/default_types.rs): FFT-friendly. -- [Base field of BLS12-381](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs) and its quadratic, sextic and twelth degree extensions. +- [Scalar field of BN-254](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bn_254/default_types.rs), and its quadratic extension, quartic, sextic and twelth degree extensions. This coincides with the base field of [Grumpkin](../elliptic_curve/short_weierstrass/curves/grumpkin/curve.rs) +- [Base field of BN-254](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bn_254/field_extension.rs) and its quadratic extension. The base field coincides with the scalar field of [Grumpkin](../elliptic_curve/short_weierstrass/curves/grumpkin/curve.rs) +- [Scalar field of BLS12-381](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/default_types.rs), and its quadratic, sextic and twelth degree extensions. FFT-friendly. +- [Base field of BLS12-381](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/field_extension.rs) - [Scalar field of BLS12-377](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/curve.rs) - [Base field of BLS12-377](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/field_extension.rs) - [Base field of secp256k1](./fields/secp256k1_field.rs): the base field of Bitcoin's elliptic curve. @@ -233,11 +233,134 @@ Multiplication follows `cios`, unless there are spare bits in the modulus. For t Inversion is performed using Algorithm 16 (Binary Euclidean Algorithm) from [Guajardo, Kumar, Paar, Perzl](https://www.sandeep.de/my/papers/2006_ActaApplMath_EfficientSoftFiniteF.pdf). +## Extension fields + +In some applications in Cryptography, it may be necessary to work over an *extension field*. For example, to compute pairings we need to work over a larger field. Similarly, in STARKs, when we need to sample a random number, we want to do it from a large set, and we can do this by working with an extension of the original field. What are extension fields? You may have heard about [complex numbers](https://en.wikipedia.org/wiki/Complex_number). We can view them as a pair of real numbers $c = (a, b)$ with a multiplication operation defined as $(a_0 , b_0 ) \times (a_1 , b_1 ) = (a_0 a_1 - b_0 b_1 , a_0 b_1 + a_1 b_0 )$ and the addition as $(a_0 , b_0 ) + (a_1 , b_1 ) = (a_0 + a_1 , b_0 + b_1 )$. We can see real numbers as a subset of $\mathbb{C}$ of the form $(a , 0)$. It is common to introduce the imaginary unit, $i$, and write them also as $a + b i$, with $i^2 = - 1$ (you can check that $(0 , 1)^2 = - 1$). We see that when work with complex numbers of the form $(a , 0)$ this works as ordinary real numbers, and we see that complex numbers extend the real numbers, allowing us to find solutions to equations that cannot be solved over the real numbers. For example, $x^2 + 1 = 0$ does not have a solution over $\mathbb{R}$, but over $\mathbb{C}$ both $i$ and $- i$ solve the equation. We will focus on how to build the complex numbers from the real numbers, and then explain how to adapt this to the setting of finite fields. + +We will work with univariate polynomials over the real numbers. A univariate polynomial over the real numbers is an expression in an indeterminate, $x$, with coefficients taking their values over the real numbers, with the following form $p(x) = a_0 + a_1 x + a_2 x^2 + \dots + a_n x^n$. For example, $p(x) = \sqrt{2} + \pi x + 2 x^2 + 5x^3 - 56 x^4$. We can add, subtract and multiply polynomials similar to what we do with integers, which means that the polynomials form a ring. We denote the ring of polynomials over real numbers as $\mathbb{R} [x]$, the ring of polynomials over the integers as $\mathbb{Z} [x]$ and the ring of polynomials over a finite field as $\mathbb{F_p} [x]$. The highest $k$ such that $a_k \neq 0$ is called the degree of the polynomial; for our previous example it is 4. Given polynomials $p(x)$ and $d(x)$, there are polynomials $q(x)$ and $r(x)$ such that $p(x) = d(x)q(x) + r(x)$, with the degree of $r(x)$ less than the degree of $d(x)$ (this in analogous to the integer division with remainder). Given a polynomial $p(x)$, we can define the ring of polynomials modulo $p(x)$, denoted by $\mathbb{R} [x] / p(x)$. Operations in this ring work similar to integers: whenever the degree of the result exceeds or equals the degree of $p(x)$, we take the remainder $r(x)$ of the division between the result and $p(x)$ (basically, $p(x)$ acts like the modulus in finite fields). + +Many polynomials can be expressed in terms of lower degree polynomials. For example, $x^2 - 1 = (x + 1) (x - 1)$, $x^3 + 3x^2 + 3x + 1 = (x + 1)(x + 1)(x + 1)$. Over the real numbers, $I(x) = x^2 + 1$ cannot be expressed in terms of lower degree polynomials. We say that $I(x)$ is [irreducible](https://en.wikipedia.org/wiki/Irreducible_polynomial) over $\mathbb{R}$. If we consider the ring modulo an irreducible polynomial, $\mathbb{R} [x] / I(x)$, then $\mathbb{R} [x] / I(x)$ is a field. The degree of $I(x)$ is the degree of the extension. For example, in the case of the real numbers, $\mathbb{R} [x] / (x^2 + 1)$ coincides with our notion of the complex numbers. Every element there has the form $a + b x$. + +Addition (and subtraction) is done the usual way, $(a + b x) + (c + dx) = (a + c) + (b + d)x$. Multiplication is a bit more difficult, $(a + bx) \times (c + dx) = ac + (b c + a d) x + b d x^2$. But this polynomial has equal degree than $x^2 + 1$, so we take the remainder. The result is $ac - bd + (b c + a d)x$ (you can check that $x^2 = - 1$). + +In the case of complex numbers, we don't need to continue extending them further, since we can factor any polynomial over $\mathbb{C}$ (see the [fundamental theorem of algebra](https://en.wikipedia.org/wiki/Fundamental_theorem_of_algebra)). + +The recipe to build extension fields over finite fields is the same. We will start with the simplest case, when $\mathbb{F_p}$ is a prime field. For example, we are working with $p = 2^{31} - 1$, a Mersenne prime (we can see that $p \equiv 3 \pmod{4}$). We consider the polynomials with coefficients over $\mathbb{F_p} [x]$. It can be shown that $- 1$ has no square root over $\mathbb{F_p}$: this means that there is no $x$ such that $x^2 = - 1$ over $\mathbb{F_p}$. The polynomial $I(x) = x^2 + 1$ is, therefore, irreducible over $\mathbb{F_p}$ (note, $x^2 - 1$ is not always irreducible over arbitrary fields!). We can consider then $\mathbb{F_p} [x] / I(x)$ and the elements there are represented by $a + b x$. One caveat with the case of complex numbers is that the operations involving $a$ and $b$ are the operations of $\mathbb{F_p }$. For example, $(5 + 2^{31} x) + ((2^{31} - 6) - x) = 0 + 0x$. Since the degree of $I(x)$ is $2$, we say that we have a quadratic extension of $\mathbb{F_p}$ and will denote it $\mathbb{F_{ p^2 } }$. You could have chosen a different degree $2$ irreducible polynomial, but we can show that the two extensions are isomorphic. + +You can build other extensions looking for higher-degree irreducible polynomials. For example, if you consider the field $\mathbb{F_2} = \{0 , 1 \}$, the polynomial $x^8 + x^4 + x^3 + x + 1$ is irreducible, and you can define a degree $8$ extension of $\mathbb{F_2}$. + +There are different ways in which we can construct higher-degree extensions. For example, we can take our prime field and find an irreducible polynomial of degree $4$ and work with $\mathbb{F_p} / I(x)$. Each element in the field can be represented as $a + b x + c x^2 + dx^3$. We can also use a towered approach: we first find an irreducible polynomial $I(x)$ of degree $2$ and obtain $\mathbb{F_{ p^2 } } = \mathbb{F_p} / I(x)$. Each element is of the form $a + b x$. Since the extension is also a field, we can find an irreducible polynomial over ${F_{ p^2 } }$, $J(y)$, of degree $2$ and consider ${F_{ p^2 } } [y] / J(y)$. Then, each element there is of the form $a^\prime + b^\prime y$, where $a^\prime$ and $b^\prime$ live in ${F_{ p^2 } }$. Since every element in ${F_{ p^2 } }$ is of the form $a_0 + a_1 x$, we get that $a_0 + a_1 x + b_0 y + b_1 x y$. Even though the extensions look different, there is an isomorphism connecting the two. Depending on the application, one form or the other can be more efficient. + +While some of the underlying concepts can be difficult to grasp, defining extension fields is simpler in lambdaworks. While we could allow you to define arbitrary extensions, we provide methods to define quadratic and cubic extensions over fields. To define a quadratic extension, you need to implement the following trait: + +```rust +pub trait HasQuadraticNonResidue { + fn residue() -> FieldElement; +} +``` + +Here, we assume that you want to define a quadratic extension of the form $x^2 - \mathrm{residue}$, where $\mathrm{residue}$ is not a square over your field. In the case of the Mersenne prime $2^{31} - 1$, $\mathrm{residue} = - 1$ (you could use other quadratic non-residues, but this can lead to slower field extension operations). Similarly, for cubic extensions we have + +```rust +pub trait HasCubicNonResidue { + /// This function must return an element that is not a cube in Fp, + /// that is, a cubic non-residue. + fn residue() -> FieldElement; +} +``` + +For example, the following code defines the default quadratic extension for BabyBear: + +```rust +pub type QuadraticBabybearField = + QuadraticExtensionField; + +impl HasQuadraticNonResidue for Babybear31PrimeField { + fn residue() -> FieldElement { + -FieldElement::one() + } +} + +/// Field element type for the quadratic extension of Babybear +pub type QuadraticBabybearFieldElement = + QuadraticExtensionFieldElement; +``` + +You can also create a separate quadratic extension by implementing the `IsField` trait for the quadratic extension, + +```rust +#[derive(Clone, Debug)] +pub struct BLS12381FieldModulus; +impl IsModulus for BLS12381FieldModulus { + const MODULUS: U384 = BLS12381_PRIME_FIELD_ORDER; +} + +pub type BLS12381PrimeField = MontgomeryBackendPrimeField; + +////////////////// +#[derive(Clone, Debug)] +pub struct Degree2ExtensionField; + +impl IsField for Degree2ExtensionField { + type BaseType = [FieldElement; 2]; + /// Returns the component wise addition of `a` and `b` + fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [&a[0] + &b[0], &a[1] + &b[1]] + } + + /// Returns the multiplication of `a` and `b` using the following + /// equation: + /// (a0 + a1 * t) * (b0 + b1 * t) = a0 * b0 + a1 * b1 * Self::residue() + (a0 * b1 + a1 * b0) * t + /// where `t.pow(2)` equals `Q::residue()`. + fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + let a0b0 = &a[0] * &b[0]; + let a1b1 = &a[1] * &b[1]; + let z = (&a[0] + &a[1]) * (&b[0] + &b[1]); + [&a0b0 - &a1b1, z - a0b0 - a1b1] + } +} +``` + +You should then implement the operations for the field, such as addition, multiplication, subtraction, inversion and so on. This is more convenient if you can avoid doing extra operations and defining the residue. You can also optimize the operations between elements of the base field and the extension field by implementing the trait `IsSubFieldOf`. + +```rust +impl IsSubFieldOf for BLS12381PrimeField { + fn mul( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let c0 = FieldElement::from_raw(::mul(a, b[0].value())); + let c1 = FieldElement::from_raw(::mul(a, b[1].value())); + [c0, c1] + } +} +``` + +Once you have the quadratic extension, you can build another extension (tower approach). For example, to define a degree 3 extension field over the quadratic extension of the BLS12-381 scalar field, we have + +```rust +#[derive(Debug, Clone)] +pub struct LevelTwoResidue; +impl HasCubicNonResidue for LevelTwoResidue { + fn residue() -> FieldElement { + FieldElement::new([ + FieldElement::new(U384::from("1")), + FieldElement::new(U384::from("1")), + ]) + } +} + +pub type Degree6ExtensionField = CubicExtensionField; +``` + +This defines a 6th degree extension over the scalar field of BLS12-381. We only need to define the cubic (non) residue, which is an element of $\mathbb{F_{ p^2 } }$. + ## Exercises - Define the base field of the Ed25519 elliptic curve, defined by the prime $p$. - Check whether $- 1$ is a quadratic residue. -- Compute $100^{65537} \pmod p$ +- Compute $100^{65537} \pmod p$ +- Define a degree 4 extension of the BabyBear field. ## References diff --git a/math/src/field/fields/fft_friendly/mod.rs b/math/src/field/fields/fft_friendly/mod.rs index a9b2f0f2e..535b94ecc 100644 --- a/math/src/field/fields/fft_friendly/mod.rs +++ b/math/src/field/fields/fft_friendly/mod.rs @@ -2,6 +2,8 @@ pub mod babybear; /// Implemenation of the quadratic extension of the babybear field pub mod quadratic_babybear; +/// Implementation of the prime field used in [Stark101](https://starkware.co/stark-101/) tutorial, p = 3 * 2^30 + 1 +pub mod stark_101_prime_field; /// Implementation of two-adic prime field over 256 bit unsigned integers. pub mod stark_252_prime_field; /// Implemenation of the Goldilocks Prime Field p = 2^64 - 2^32 + 1 diff --git a/math/src/field/fields/fft_friendly/stark_101_prime_field.rs b/math/src/field/fields/fft_friendly/stark_101_prime_field.rs new file mode 100644 index 000000000..d6232a414 --- /dev/null +++ b/math/src/field/fields/fft_friendly/stark_101_prime_field.rs @@ -0,0 +1,113 @@ +use crate::{ + field::{ + element::FieldElement, + fields::montgomery_backed_prime_fields::{IsModulus, U64PrimeField}, + traits::IsFFTField, + }, + unsigned_integer::element::{UnsignedInteger, U64}, +}; + +#[derive(Clone, Debug, Hash, Copy)] +pub struct MontgomeryConfigStark101PrimeField; +impl IsModulus for MontgomeryConfigStark101PrimeField { + /// 3 * 2^30 + 1 + const MODULUS: U64 = U64::from_hex_unchecked("c0000001"); +} + +pub type Stark101PrimeField = U64PrimeField; + +impl IsFFTField for Stark101PrimeField { + const TWO_ADICITY: u64 = 30; + + const TWO_ADIC_PRIMITVE_ROOT_OF_UNITY: U64 = UnsignedInteger::from_hex_unchecked("bb6e79d"); + + fn field_name() -> &'static str { + "stark101" + } +} + +impl FieldElement { + pub fn to_bytes_le(&self) -> [u8; 8] { + let limbs = self.representative().limbs; + limbs[0].to_le_bytes() + } + + pub fn to_bytes_be(&self) -> [u8; 8] { + let limbs = self.representative().limbs; + limbs[0].to_be_bytes() + } +} + +#[allow(clippy::non_canonical_partial_ord_impl)] +impl PartialOrd for FieldElement { + fn partial_cmp(&self, other: &Self) -> Option { + self.representative().partial_cmp(&other.representative()) + } +} + +impl Ord for FieldElement { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + self.representative().cmp(&other.representative()) + } +} + +#[cfg(test)] +mod test_stark101_prime_field { + use super::Stark101PrimeField; + use crate::{ + field::{element::FieldElement, traits::IsFFTField}, + traits::ByteConversion, + }; + + #[test] + fn two_adic_order() { + let w = FieldElement::::from( + Stark101PrimeField::TWO_ADIC_PRIMITVE_ROOT_OF_UNITY.limbs[0], + ); + + assert_eq!( + w.pow(1u64 << Stark101PrimeField::TWO_ADICITY), + FieldElement::one() + ); + assert_ne!( + w.pow(1u64 << (Stark101PrimeField::TWO_ADICITY >> 1)), + FieldElement::one() + ); + } + + #[test] + #[cfg(feature = "alloc")] + fn byte_serialization_for_a_number_matches_with_byte_conversion_implementation_le() { + let element = FieldElement::::from_hex_unchecked("0123456701234567"); + let bytes = element.to_bytes_le(); + let expected_bytes: [u8; 8] = ByteConversion::to_bytes_le(&element).try_into().unwrap(); + assert_eq!(bytes, expected_bytes); + } + + #[test] + #[cfg(feature = "alloc")] + fn byte_serialization_for_a_number_matches_with_byte_conversion_implementation_be() { + let element = FieldElement::::from_hex_unchecked("0123456701234567"); + let bytes = element.to_bytes_be(); + let expected_bytes: [u8; 8] = ByteConversion::to_bytes_be(&element).try_into().unwrap(); + assert_eq!(bytes, expected_bytes); + } + + #[test] + + fn byte_serialization_and_deserialization_works_le() { + let element = FieldElement::::from_hex_unchecked("7654321076543210"); + let bytes = element.to_bytes_le(); + let from_bytes = FieldElement::::from_bytes_le(&bytes).unwrap(); + assert_eq!(element, from_bytes); + } + + #[test] + + fn byte_serialization_and_deserialization_works_be() { + let element = FieldElement::::from_hex_unchecked("7654321076543210"); + let bytes = element.to_bytes_be(); + let from_bytes = FieldElement::::from_bytes_be(&bytes).unwrap(); + assert_eq!(element, from_bytes); + } +} diff --git a/math/src/field/fields/mersenne31/extension.rs b/math/src/field/fields/mersenne31/extension.rs deleted file mode 100644 index 3c89a2147..000000000 --- a/math/src/field/fields/mersenne31/extension.rs +++ /dev/null @@ -1,304 +0,0 @@ -use crate::field::{ - element::FieldElement, - errors::FieldError, - extensions::{ - cubic::{CubicExtensionField, HasCubicNonResidue}, - quadratic::{HasQuadraticNonResidue, QuadraticExtensionField}, - }, - traits::IsField, -}; - -use super::field::Mersenne31Field; - -//Note: The inverse calculation in mersenne31/plonky3 differs from the default quadratic extension so I implemented the complex extension. -////////////////// -#[derive(Clone, Debug)] -pub struct Mersenne31Complex; - -impl IsField for Mersenne31Complex { - //Elements represents a[0] = real, a[1] = imaginary - type BaseType = [FieldElement; 2]; - - /// Returns the component wise addition of `a` and `b` - fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - [a[0] + b[0], a[1] + b[1]] - } - - //NOTE: THIS uses Gauss algorithm. Bench this against plonky 3 implementation to see what is faster. - /// Returns the multiplication of `a` and `b` using the following - /// equation: - /// (a0 + a1 * t) * (b0 + b1 * t) = a0 * b0 + a1 * b1 * Self::residue() + (a0 * b1 + a1 * b0) * t - /// where `t.pow(2)` equals `Q::residue()`. - fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - let a0b0 = a[0] * b[0]; - let a1b1 = a[1] * b[1]; - let z = (a[0] + a[1]) * (b[0] + b[1]); - [a0b0 - a1b1, z - a0b0 - a1b1] - } - - fn square(a: &Self::BaseType) -> Self::BaseType { - let [a0, a1] = a; - let v0 = a0 * a1; - let c0 = (a0 + a1) * (a0 - a1); - let c1 = v0 + v0; - [c0, c1] - } - /// Returns the component wise subtraction of `a` and `b` - fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - [a[0] - b[0], a[1] - b[1]] - } - - /// Returns the component wise negation of `a` - fn neg(a: &Self::BaseType) -> Self::BaseType { - [-a[0], -a[1]] - } - - /// Returns the multiplicative inverse of `a` - fn inv(a: &Self::BaseType) -> Result { - let inv_norm = (a[0].pow(2_u64) + a[1].pow(2_u64)).inv()?; - Ok([a[0] * inv_norm, -a[1] * inv_norm]) - } - - /// Returns the division of `a` and `b` - fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { - Self::mul(a, &Self::inv(b).unwrap()) - } - - /// Returns a boolean indicating whether `a` and `b` are equal component wise. - fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { - a[0] == b[0] && a[1] == b[1] - } - - /// Returns the additive neutral element of the field extension. - fn zero() -> Self::BaseType { - [FieldElement::zero(), FieldElement::zero()] - } - - /// Returns the multiplicative neutral element of the field extension. - fn one() -> Self::BaseType { - [FieldElement::one(), FieldElement::zero()] - } - - /// Returns the element `x * 1` where 1 is the multiplicative neutral element. - fn from_u64(x: u64) -> Self::BaseType { - [FieldElement::from(x), FieldElement::zero()] - } - - /// Takes as input an element of BaseType and returns the internal representation - /// of that element in the field. - /// Note: for this case this is simply the identity, because the components - /// already have correct representations. - fn from_base_type(x: Self::BaseType) -> Self::BaseType { - x - } -} - -pub type Mersenne31ComplexQuadraticExtensionField = - QuadraticExtensionField; - -//TODO: Check this should be for complex and not base field -impl HasQuadraticNonResidue for Mersenne31Complex { - // Verifiable in Sage with - // ```sage - // p = 2**31 - 1 # Mersenne31 - // F = GF(p) # The base field GF(p) - // R. = F[] # The polynomial ring over F - // K. = F.extension(x^2 + 1) # The complex extension field - // R2. = K[] - // f2 = y^2 - i - 2 - // assert f2.is_irreducible() - // ``` - fn residue() -> FieldElement { - FieldElement::from(&Mersenne31Complex::from_base_type([ - FieldElement::::from(2), - FieldElement::::one(), - ])) - } -} - -pub type Mersenne31ComplexCubicExtensionField = - CubicExtensionField; - -impl HasCubicNonResidue for Mersenne31Complex { - // Verifiable in Sage with - // ```sage - // p = 2**31 - 1 # Mersenne31 - // F = GF(p) # The base field GF(p) - // R. = F[] # The polynomial ring over F - // K. = F.extension(x^2 + 1) # The complex extension field - // R2. = K[] - // f2 = y^3 - 5*i - // assert f2.is_irreducible() - // ``` - fn residue() -> FieldElement { - FieldElement::from(&Mersenne31Complex::from_base_type([ - FieldElement::::zero(), - FieldElement::::from(5), - ])) - } -} - -#[cfg(test)] -mod tests { - use crate::field::fields::mersenne31::field::MERSENNE_31_PRIME_FIELD_ORDER; - - use super::*; - - type Fi = Mersenne31Complex; - type F = FieldElement; - - //NOTE: from_u64 reflects from_real - //NOTE: for imag use from_base_type - - #[test] - fn add_real_one_plus_one_is_two() { - assert_eq!(Fi::add(&Fi::one(), &Fi::one()), Fi::from_u64(2)) - } - - #[test] - fn add_real_neg_one_plus_one_is_zero() { - assert_eq!(Fi::add(&Fi::neg(&Fi::one()), &Fi::one()), Fi::zero()) - } - - #[test] - fn add_real_neg_one_plus_two_is_one() { - assert_eq!(Fi::add(&Fi::neg(&Fi::one()), &Fi::from_u64(2)), Fi::one()) - } - - #[test] - fn add_real_neg_one_plus_neg_one_is_order_sub_two() { - assert_eq!( - Fi::add(&Fi::neg(&Fi::one()), &Fi::neg(&Fi::one())), - Fi::from_u64((MERSENNE_31_PRIME_FIELD_ORDER - 2).into()) - ) - } - - #[test] - fn add_complex_one_plus_one_two() { - //Manually declare the complex part to one - let one = Fi::from_base_type([F::zero(), F::one()]); - let two = Fi::from_base_type([F::zero(), F::from(2)]); - assert_eq!(Fi::add(&one, &one), two) - } - - #[test] - fn add_complex_neg_one_plus_one_is_zero() { - //Manually declare the complex part to one - let neg_one = Fi::from_base_type([F::zero(), -F::one()]); - let one = Fi::from_base_type([F::zero(), F::one()]); - assert_eq!(Fi::add(&neg_one, &one), Fi::zero()) - } - - #[test] - fn add_complex_neg_one_plus_two_is_one() { - let neg_one = Fi::from_base_type([F::zero(), -F::one()]); - let two = Fi::from_base_type([F::zero(), F::from(2)]); - let one = Fi::from_base_type([F::zero(), F::one()]); - assert_eq!(Fi::add(&neg_one, &two), one) - } - - #[test] - fn add_complex_neg_one_plus_neg_one_imag_is_order_sub_two() { - let neg_one = Fi::from_base_type([F::zero(), -F::one()]); - assert_eq!( - Fi::add(&neg_one, &neg_one)[1], - F::new(MERSENNE_31_PRIME_FIELD_ORDER - 2) - ) - } - - #[test] - fn add_order() { - let a = Fi::from_base_type([-F::one(), F::one()]); - let b = Fi::from_base_type([F::from(2), F::new(MERSENNE_31_PRIME_FIELD_ORDER - 2)]); - let c = Fi::from_base_type([F::one(), -F::one()]); - assert_eq!(Fi::add(&a, &b), c) - } - - #[test] - fn add_equal_zero() { - let a = Fi::from_base_type([-F::one(), -F::one()]); - let b = Fi::from_base_type([F::one(), F::one()]); - assert_eq!(Fi::add(&a, &b), Fi::zero()) - } - - #[test] - fn add_plus_one() { - let a = Fi::from_base_type([F::one(), F::from(2)]); - let b = Fi::from_base_type([F::one(), F::one()]); - let c = Fi::from_base_type([F::from(2), F::from(3)]); - assert_eq!(Fi::add(&a, &b), c) - } - - #[test] - fn sub_real_one_sub_one_is_zero() { - assert_eq!(Fi::sub(&Fi::one(), &Fi::one()), Fi::zero()) - } - - #[test] - fn sub_real_two_sub_two_is_zero() { - assert_eq!( - Fi::sub(&Fi::from_u64(2u64), &Fi::from_u64(2u64)), - Fi::zero() - ) - } - - #[test] - fn sub_real_neg_one_sub_neg_one_is_zero() { - assert_eq!( - Fi::sub(&Fi::neg(&Fi::one()), &Fi::neg(&Fi::one())), - Fi::zero() - ) - } - - #[test] - fn sub_real_two_sub_one_is_one() { - assert_eq!(Fi::sub(&Fi::from_u64(2), &Fi::one()), Fi::one()) - } - - #[test] - fn sub_real_neg_one_sub_zero_is_neg_one() { - assert_eq!( - Fi::sub(&Fi::neg(&Fi::one()), &Fi::zero()), - Fi::neg(&Fi::one()) - ) - } - - #[test] - fn sub_complex_one_sub_one_is_zero() { - let one = Fi::from_base_type([F::zero(), F::one()]); - assert_eq!(Fi::sub(&one, &one), Fi::zero()) - } - - #[test] - fn sub_complex_two_sub_two_is_zero() { - let two = Fi::from_base_type([F::zero(), F::from(2)]); - assert_eq!(Fi::sub(&two, &two), Fi::zero()) - } - - #[test] - fn sub_complex_neg_one_sub_neg_one_is_zero() { - let neg_one = Fi::from_base_type([F::zero(), -F::one()]); - assert_eq!(Fi::sub(&neg_one, &neg_one), Fi::zero()) - } - - #[test] - fn sub_complex_two_sub_one_is_one() { - let two = Fi::from_base_type([F::zero(), F::from(2)]); - let one = Fi::from_base_type([F::zero(), F::one()]); - assert_eq!(Fi::sub(&two, &one), one) - } - - #[test] - fn sub_complex_neg_one_sub_zero_is_neg_one() { - let neg_one = Fi::from_base_type([F::zero(), -F::one()]); - assert_eq!(Fi::sub(&neg_one, &Fi::zero()), neg_one) - } - - #[test] - fn mul() { - let a = Fi::from_base_type([F::from(2), F::from(2)]); - let b = Fi::from_base_type([F::from(4), F::from(5)]); - let c = Fi::from_base_type([-F::from(2), F::from(18)]); - assert_eq!(Fi::mul(&a, &b), c) - } -} diff --git a/math/src/field/fields/mersenne31/extensions.rs b/math/src/field/fields/mersenne31/extensions.rs new file mode 100644 index 000000000..27c2ab118 --- /dev/null +++ b/math/src/field/fields/mersenne31/extensions.rs @@ -0,0 +1,627 @@ +use super::field::Mersenne31Field; +use crate::field::{ + element::FieldElement, + errors::FieldError, + traits::{IsField, IsSubFieldOf}, +}; +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +type FpE = FieldElement; + +#[derive(Clone, Debug)] +pub struct Degree2ExtensionField; + +impl Degree2ExtensionField { + pub fn mul_fp2_by_nonresidue(a: &Fp2E) -> Fp2E { + Fp2E::new([ + a.value()[0].double() - a.value()[1], + a.value()[1].double() + a.value()[0], + ]) + } +} + +impl IsField for Degree2ExtensionField { + //Element representation: a[0] = real part, a[1] = imaginary part + type BaseType = [FpE; 2]; + + /// Returns the component wise addition of `a` and `b` + fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [a[0] + b[0], a[1] + b[1]] + } + + /// Returns the multiplication of `a` and `b`. + fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + let a0b0 = a[0] * b[0]; + let a1b1 = a[1] * b[1]; + let z = (a[0] + a[1]) * (b[0] + b[1]); + [a0b0 - a1b1, z - a0b0 - a1b1] + } + + fn square(a: &Self::BaseType) -> Self::BaseType { + let [a0, a1] = a; + let v0 = a0 * a1; + let c0 = (a0 + a1) * (a0 - a1); + let c1 = v0.double(); + [c0, c1] + } + /// Returns the component wise subtraction of `a` and `b` + fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [a[0] - b[0], a[1] - b[1]] + } + + /// Returns the component wise negation of `a` + fn neg(a: &Self::BaseType) -> Self::BaseType { + [-a[0], -a[1]] + } + + /// Returns the multiplicative inverse of `a` + fn inv(a: &Self::BaseType) -> Result { + let inv_norm = (a[0].square() + a[1].square()).inv()?; + Ok([a[0] * inv_norm, -a[1] * inv_norm]) + } + + /// Returns the division of `a` and `b` + fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + ::mul(a, &Self::inv(b).unwrap()) + } + + /// Returns a boolean indicating whether `a` and `b` are equal component wise. + fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { + a[0] == b[0] && a[1] == b[1] + } + + /// Returns the multiplicative neutral element of the field extension. + fn one() -> Self::BaseType { + [FpE::one(), FpE::zero()] + } + + /// Returns the element `x * 1` where 1 is the multiplicative neutral element. + fn from_u64(x: u64) -> Self::BaseType { + [FpE::from(x), FpE::zero()] + } + + /// Takes as input an element of BaseType and returns the internal representation + /// of that element in the field. + /// Note: for this case this is simply the identity, because the components + /// already have correct representations. + fn from_base_type(x: Self::BaseType) -> Self::BaseType { + x + } +} + +impl IsSubFieldOf for Mersenne31Field { + fn add( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + [FpE::from(a) + b[0], b[1]] + } + + fn sub( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + [FpE::from(a) - b[0], -b[1]] + } + + fn mul( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + [FpE::from(a) * b[0], FpE::from(a) * b[1]] + } + + fn div( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let b_inv = Degree2ExtensionField::inv(b).unwrap(); + >::mul(a, &b_inv) + } + + fn embed(a: Self::BaseType) -> ::BaseType { + [FieldElement::from_raw(a), FieldElement::zero()] + } + + #[cfg(feature = "alloc")] + fn to_subfield_vec( + b: ::BaseType, + ) -> alloc::vec::Vec { + b.into_iter().map(|x| x.to_raw()).collect() + } +} + +type Fp2E = FieldElement; + +#[derive(Clone, Debug)] +pub struct Degree4ExtensionField; + +impl IsField for Degree4ExtensionField { + type BaseType = [Fp2E; 2]; + + fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [&a[0] + &b[0], &a[1] + &b[1]] + } + + fn sub(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + [&a[0] - &b[0], &a[1] - &b[1]] + } + + fn neg(a: &Self::BaseType) -> Self::BaseType { + [-&a[0], -&a[1]] + } + + fn mul(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + // Algorithm from: https://github.com/ingonyama-zk/papers/blob/main/Mersenne31_polynomial_arithmetic.pdf (page 5): + let a0b0 = &a[0] * &b[0]; + let a1b1 = &a[1] * &b[1]; + [ + &a0b0 + Degree2ExtensionField::mul_fp2_by_nonresidue(&a1b1), + (&a[0] + &a[1]) * (&b[0] + &b[1]) - a0b0 - a1b1, + ] + } + + fn square(a: &Self::BaseType) -> Self::BaseType { + let a0_square = &a[0].square(); + let a1_square = &a[1].square(); + [ + a0_square + Degree2ExtensionField::mul_fp2_by_nonresidue(a1_square), + (&a[0] + &a[1]).square() - a0_square - a1_square, + ] + } + + fn inv(a: &Self::BaseType) -> Result { + let inv_norm = + (a[0].square() - Degree2ExtensionField::mul_fp2_by_nonresidue(&a[1].square())).inv()?; + Ok([&a[0] * &inv_norm, -&a[1] * &inv_norm]) + } + + fn div(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType { + ::mul(a, &Self::inv(b).unwrap()) + } + + fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool { + a[0] == b[0] && a[1] == b[1] + } + + fn zero() -> Self::BaseType { + [Fp2E::zero(), Fp2E::zero()] + } + + fn one() -> Self::BaseType { + [Fp2E::one(), Fp2E::zero()] + } + + fn from_u64(x: u64) -> Self::BaseType { + [Fp2E::from(x), Fp2E::zero()] + } + + fn from_base_type(x: Self::BaseType) -> Self::BaseType { + x + } +} + +impl IsSubFieldOf for Mersenne31Field { + fn add( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + [FpE::from(a) + &b[0], b[1].clone()] + } + + fn sub( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + [FpE::from(a) - &b[0], -&b[1]] + } + + fn mul( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let c0 = FpE::from(a) * &b[0]; + let c1 = FpE::from(a) * &b[1]; + [c0, c1] + } + + fn div( + a: &Self::BaseType, + b: &::BaseType, + ) -> ::BaseType { + let b_inv = Degree4ExtensionField::inv(b).unwrap(); + >::mul(a, &b_inv) + } + + fn embed(a: Self::BaseType) -> ::BaseType { + [ + Fp2E::from_raw(>::embed(a)), + Fp2E::zero(), + ] + } + + #[cfg(feature = "alloc")] + fn to_subfield_vec( + b: ::BaseType, + ) -> alloc::vec::Vec { + // TODO: Repace this for with a map similarly to this: + // b.into_iter().map(|x| x.to_raw()).collect() + let mut result = Vec::new(); + for fp2e in b { + result.push(fp2e.value()[0].to_raw()); + result.push(fp2e.value()[1].to_raw()); + } + result + } +} + +#[cfg(test)] +mod tests { + use core::ops::Neg; + + use crate::field::fields::mersenne31::field::MERSENNE_31_PRIME_FIELD_ORDER; + + use super::*; + + type FpE = FieldElement; + type Fp2E = FieldElement; + type Fp4E = FieldElement; + + #[test] + fn add_real_one_plus_one_is_two() { + assert_eq!(Fp2E::one() + Fp2E::one(), Fp2E::from(2)) + } + + #[test] + fn add_real_neg_one_plus_one_is_zero() { + assert_eq!(Fp2E::one() + Fp2E::one().neg(), Fp2E::zero()) + } + + #[test] + fn add_real_neg_one_plus_two_is_one() { + assert_eq!(Fp2E::one().neg() + Fp2E::from(2), Fp2E::one()) + } + + #[test] + fn add_real_neg_one_plus_neg_one_is_order_sub_two() { + assert_eq!( + Fp2E::one().neg() + Fp2E::one().neg(), + Fp2E::new([FpE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 2)), FpE::zero()]) + ) + } + + #[test] + fn add_complex_one_plus_one_two() { + let one_i = Fp2E::new([FpE::zero(), FpE::one()]); + let two_i = Fp2E::new([FpE::zero(), FpE::from(2)]); + assert_eq!(&one_i + &one_i, two_i) + } + + #[test] + fn add_complex_neg_one_plus_one_is_zero() { + //Manually declare the complex part to one + let neg_one_i = Fp2E::new([FpE::zero(), -FpE::one()]); + let one_i = Fp2E::new([FpE::zero(), FpE::one()]); + assert_eq!(neg_one_i + one_i, Fp2E::zero()) + } + + #[test] + fn add_complex_neg_one_plus_two_is_one() { + let neg_one_i = Fp2E::new([FpE::zero(), -FpE::one()]); + let two_i = Fp2E::new([FpE::zero(), FpE::from(2)]); + let one_i = Fp2E::new([FpE::zero(), FpE::one()]); + assert_eq!(&neg_one_i + &two_i, one_i) + } + + #[test] + fn add_complex_neg_one_plus_neg_one_imag_is_order_sub_two() { + let neg_one_i = Fp2E::new([FpE::zero(), -FpE::one()]); + assert_eq!( + (&neg_one_i + &neg_one_i).value()[1], + FpE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 2)) + ) + } + + #[test] + fn add_order() { + let a = Fp2E::new([-FpE::one(), FpE::one()]); + let b = Fp2E::new([ + FpE::from(2), + FpE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 2)), + ]); + let c = Fp2E::new([FpE::one(), -FpE::one()]); + assert_eq!(&a + &b, c) + } + + #[test] + fn add_equal_zero() { + let a = Fp2E::new([-FpE::one(), -FpE::one()]); + let b = Fp2E::new([FpE::one(), FpE::one()]); + assert_eq!(&a + &b, Fp2E::zero()) + } + + #[test] + fn add_plus_one() { + let a = Fp2E::new([FpE::one(), FpE::from(2)]); + let b = Fp2E::new([FpE::one(), FpE::one()]); + let c = Fp2E::new([FpE::from(2), FpE::from(3)]); + assert_eq!(&a + &b, c) + } + + #[test] + fn sub_real_one_sub_one_is_zero() { + assert_eq!(&Fp2E::one() - &Fp2E::one(), Fp2E::zero()) + } + + #[test] + fn sub_real_two_sub_two_is_zero() { + assert_eq!(&Fp2E::from(2) - &Fp2E::from(2), Fp2E::zero()) + } + + #[test] + fn sub_real_neg_one_sub_neg_one_is_zero() { + assert_eq!(Fp2E::one().neg() - Fp2E::one().neg(), Fp2E::zero()) + } + + #[test] + fn sub_real_two_sub_one_is_one() { + assert_eq!(Fp2E::from(2) - Fp2E::one(), Fp2E::one()) + } + + #[test] + fn sub_real_neg_one_sub_zero_is_neg_one() { + assert_eq!(Fp2E::one().neg() - Fp2E::zero(), Fp2E::one().neg()) + } + + #[test] + fn sub_complex_one_sub_one_is_zero() { + let one = Fp2E::new([FpE::zero(), FpE::one()]); + assert_eq!(&one - &one, Fp2E::zero()) + } + + #[test] + fn sub_complex_two_sub_two_is_zero() { + let two = Fp2E::new([FpE::zero(), FpE::from(2)]); + assert_eq!(&two - &two, Fp2E::zero()) + } + + #[test] + fn sub_complex_neg_one_sub_neg_one_is_zero() { + let neg_one = Fp2E::new([FpE::zero(), -FpE::one()]); + assert_eq!(&neg_one - &neg_one, Fp2E::zero()) + } + + #[test] + fn sub_complex_two_sub_one_is_one() { + let two = Fp2E::new([FpE::zero(), FpE::from(2)]); + let one = Fp2E::new([FpE::zero(), FpE::one()]); + assert_eq!(&two - &one, one) + } + + #[test] + fn sub_complex_neg_one_sub_zero_is_neg_one() { + let neg_one = Fp2E::new([FpE::zero(), -FpE::one()]); + assert_eq!(&neg_one - &Fp2E::zero(), neg_one) + } + + #[test] + fn mul_fp2_is_correct() { + let a = Fp2E::new([FpE::from(2), FpE::from(2)]); + let b = Fp2E::new([FpE::from(4), FpE::from(5)]); + let c = Fp2E::new([-FpE::from(2), FpE::from(18)]); + assert_eq!(&a * &b, c) + } + + #[test] + fn square_equals_mul_by_itself() { + let a = Fp2E::new([FpE::from(2), FpE::from(3)]); + assert_eq!(a.square(), &a * &a) + } + + #[test] + fn test_fp2_add() { + let a = Fp2E::new([FpE::from(0), FpE::from(3)]); + let b = Fp2E::new([-FpE::from(2), FpE::from(8)]); + let expected_result = Fp2E::new([FpE::from(0) - FpE::from(2), FpE::from(3) + FpE::from(8)]); + assert_eq!(a + b, expected_result); + } + + #[test] + fn test_fp2_add_2() { + let a = Fp2E::new([FpE::from(2), FpE::from(4)]); + let b = Fp2E::new([-FpE::from(2), -FpE::from(4)]); + let expected_result = Fp2E::new([FpE::from(2) - FpE::from(2), FpE::from(4) - FpE::from(4)]); + assert_eq!(a + b, expected_result); + } + + #[test] + fn test_fp2_add_3() { + let a = Fp2E::new([FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER), FpE::from(1)]); + let b = Fp2E::new([FpE::from(1), FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER)]); + let expected_result = Fp2E::new([FpE::from(1), FpE::from(1)]); + assert_eq!(a + b, expected_result); + } + + #[test] + fn test_fp2_sub() { + let a = Fp2E::new([FpE::from(0), FpE::from(3)]); + let b = Fp2E::new([-FpE::from(2), FpE::from(8)]); + let expected_result = Fp2E::new([FpE::from(0) + FpE::from(2), FpE::from(3) - FpE::from(8)]); + assert_eq!(a - b, expected_result); + } + + #[test] + fn test_fp2_sub_2() { + let a = Fp2E::new([FpE::zero(), FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER)]); + let b = Fp2E::new([FpE::one(), -FpE::one()]); + let expected_result = + Fp2E::new([FpE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 1)), FpE::one()]); + assert_eq!(a - b, expected_result); + } + + #[test] + fn test_fp2_sub_3() { + let a = Fp2E::new([FpE::from(5), FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER)]); + let b = Fp2E::new([FpE::from(5), FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER)]); + let expected_result = Fp2E::new([FpE::zero(), FpE::zero()]); + assert_eq!(a - b, expected_result); + } + + #[test] + fn test_fp2_mul() { + let a = Fp2E::new([FpE::from(12), FpE::from(5)]); + let b = Fp2E::new([-FpE::from(4), FpE::from(2)]); + let expected_result = Fp2E::new([-FpE::from(58), FpE::new(4)]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_mul_2() { + let a = Fp2E::new([FpE::one(), FpE::zero()]); + let b = Fp2E::new([FpE::from(12), -FpE::from(8)]); + let expected_result = Fp2E::new([FpE::from(12), -FpE::new(8)]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_mul_3() { + let a = Fp2E::new([FpE::zero(), FpE::zero()]); + let b = Fp2E::new([FpE::from(2), FpE::from(7)]); + let expected_result = Fp2E::new([FpE::zero(), FpE::zero()]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_mul_4() { + let a = Fp2E::new([FpE::from(2), FpE::from(7)]); + let b = Fp2E::new([FpE::zero(), FpE::zero()]); + let expected_result = Fp2E::new([FpE::zero(), FpE::zero()]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_mul_5() { + let a = Fp2E::new([FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER), FpE::one()]); + let b = Fp2E::new([FpE::from(2), FpE::from(&MERSENNE_31_PRIME_FIELD_ORDER)]); + let expected_result = Fp2E::new([FpE::zero(), FpE::from(2)]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_inv() { + let a = Fp2E::new([FpE::one(), FpE::zero()]); + let expected_result = Fp2E::new([FpE::one(), FpE::zero()]); + assert_eq!(a.inv().unwrap(), expected_result); + } + + #[test] + fn test_fp2_inv_2() { + let a = Fp2E::new([FpE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 1)), FpE::one()]); + let expected_result = Fp2E::new([FpE::from(1073741823), FpE::from(1073741823)]); + assert_eq!(a.inv().unwrap(), expected_result); + } + + #[test] + fn test_fp2_inv_3() { + let a = Fp2E::new([FpE::from(2063384121), FpE::from(1232183486)]); + let expected_result = Fp2E::new([FpE::from(1244288232), FpE::from(1321511038)]); + assert_eq!(a.inv().unwrap(), expected_result); + } + + #[test] + fn test_fp2_mul_inv() { + let a = Fp2E::new([FpE::from(12), FpE::from(5)]); + let b = a.inv().unwrap(); + let expected_result = Fp2E::new([FpE::one(), FpE::zero()]); + assert_eq!(a * b, expected_result); + } + + #[test] + fn test_fp2_div() { + let a = Fp2E::new([FpE::from(12), FpE::from(5)]); + let b = Fp2E::new([FpE::from(4), FpE::from(2)]); + let expected_result = Fp2E::new([FpE::from(644245097), FpE::from(1288490188)]); + assert_eq!(a / b, expected_result); + } + + #[test] + fn test_fp2_div_2() { + let a = Fp2E::new([FpE::from(4), FpE::from(7)]); + let b = Fp2E::new([FpE::one(), FpE::zero()]); + let expected_result = Fp2E::new([FpE::from(4), FpE::from(7)]); + assert_eq!(a / b, expected_result); + } + + #[test] + fn test_fp2_div_3() { + let a = Fp2E::new([FpE::zero(), FpE::zero()]); + let b = Fp2E::new([FpE::from(3), FpE::from(12)]); + let expected_result = Fp2E::new([FpE::zero(), FpE::zero()]); + assert_eq!(a / b, expected_result); + } + + #[test] + fn mul_fp4_by_zero_is_zero() { + let a = Fp4E::new([ + Fp2E::new([FpE::from(2), FpE::from(3)]), + Fp2E::new([FpE::from(4), FpE::from(5)]), + ]); + assert_eq!(Fp4E::zero(), a * Fp4E::zero()) + } + + #[test] + fn mul_fp4_by_one_is_identity() { + let a = Fp4E::new([ + Fp2E::new([FpE::from(2), FpE::from(3)]), + Fp2E::new([FpE::from(4), FpE::from(5)]), + ]); + assert_eq!(a, a.clone() * Fp4E::one()) + } + + #[test] + fn square_fp4_equals_mul_two_times() { + let a = Fp4E::new([ + Fp2E::new([FpE::from(3), FpE::from(4)]), + Fp2E::new([FpE::from(5), FpE::from(6)]), + ]); + + assert_eq!(a.square(), &a * &a) + } + + #[test] + fn fp4_mul_by_inv_is_one() { + let a = Fp4E::new([ + Fp2E::new([FpE::from(2147483647), FpE::from(2147483648)]), + Fp2E::new([FpE::from(2147483649), FpE::from(2147483650)]), + ]); + + assert_eq!(&a * a.inv().unwrap(), Fp4E::one()) + } + + #[test] + fn embed_fp_with_fp4() { + let a = FpE::from(3); + let a_extension = Fp4E::from(3); + assert_eq!(a.to_extension::(), a_extension); + } + + #[test] + fn add_fp_and_fp4() { + let a = FpE::from(3); + let a_extension = Fp4E::from(3); + let b = Fp4E::from(2); + assert_eq!(a + &b, a_extension + b); + } + + #[test] + fn mul_fp_by_fp4() { + let a = FpE::from(30000000000); + let a_extension = a.to_extension::(); + let b = Fp4E::new([ + Fp2E::new([FpE::from(1), FpE::from(2)]), + Fp2E::new([FpE::from(3), FpE::from(4)]), + ]); + assert_eq!(a * &b, a_extension * b); + } +} diff --git a/math/src/field/fields/mersenne31/field.rs b/math/src/field/fields/mersenne31/field.rs index e4abfab0f..1c8b2dc58 100644 --- a/math/src/field/fields/mersenne31/field.rs +++ b/math/src/field/fields/mersenne31/field.rs @@ -42,6 +42,29 @@ impl Mersenne31Field { // Delayed reduction Self::from_u64(iter.map(|x| (x as u64)).sum::()) } + + /// Computes a * 2^k, with 0 < k < 31 + pub fn mul_power_two(a: u32, k: u32) -> u32 { + let msb = (a & (u32::MAX << (31 - k))) >> (31 - k); // The k + 1 msf shifted right . + let lsb = (a & (u32::MAX >> (k + 1))) << k; // The 31 - k lsb shifted left. + Self::weak_reduce(msb + lsb) + } + + pub fn pow_2(a: &u32, order: u32) -> u32 { + let mut res = *a; + (0..order).for_each(|_| res = Self::square(&res)); + res + } + + /// TODO: See if we can optimize this function. + /// Computes 2a^2 - 1 + pub fn two_square_minus_one(a: &u32) -> u32 { + if *a == 0 { + MERSENNE_31_PRIME_FIELD_ORDER - 1 + } else { + Self::from_u64(((u64::from(*a) * u64::from(*a)) << 1) - 1) + } + } } pub const MERSENNE_31_PRIME_FIELD_ORDER: u32 = (1 << 31) - 1; @@ -54,18 +77,9 @@ impl IsField for Mersenne31Field { /// Returns the sum of `a` and `b`. fn add(a: &u32, b: &u32) -> u32 { - // Avoids conditional https://github.com/Plonky3/Plonky3/blob/6049a30c3b1f5351c3eb0f7c994dc97e8f68d10d/mersenne-31/src/lib.rs#L249 - // Working with i32 means we get a flag which informs us if overflow happens - let (sum_i32, over) = (*a as i32).overflowing_add(*b as i32); - let sum_u32 = sum_i32 as u32; - let sum_corr = sum_u32.wrapping_sub(MERSENNE_31_PRIME_FIELD_ORDER); - - //assert 31 bit clear - // If self + rhs did not overflow, return it. - // If self + rhs overflowed, sum_corr = self + rhs - (2**31 - 1). - let sum = if over { sum_corr } else { sum_u32 }; - debug_assert!((sum >> 31) == 0); - Self::as_representative(&sum) + // We are using that if a and b are field elements of Mersenne31, then + // a + b has at most 32 bits, so we can use the weak_reduce function to take mudulus p. + Self::weak_reduce(a + b) } /// Returns the multiplication of `a` and `b`. @@ -75,13 +89,7 @@ impl IsField for Mersenne31Field { } fn sub(a: &u32, b: &u32) -> u32 { - let (mut sub, over) = a.overflowing_sub(*b); - - // If we didn't overflow we have the correct value. - // Otherwise we have added 2**32 = 2**31 + 1 mod 2**31 - 1. - // Hence we need to remove the most significant bit and subtract 1. - sub -= over as u32; - sub & MERSENNE_31_PRIME_FIELD_ORDER + Self::weak_reduce(a + MERSENNE_31_PRIME_FIELD_ORDER - b) } /// Returns the additive inverse of `a`. @@ -91,20 +99,20 @@ impl IsField for Mersenne31Field { } /// Returns the multiplicative inverse of `a`. - fn inv(a: &u32) -> Result { - if *a == Self::zero() || *a == MERSENNE_31_PRIME_FIELD_ORDER { + fn inv(x: &u32) -> Result { + if *x == Self::zero() || *x == MERSENNE_31_PRIME_FIELD_ORDER { return Err(FieldError::InvZeroError); } - let p101 = Self::mul(&Self::pow(a, 4u32), a); + let p101 = Self::mul(&Self::pow_2(x, 2), x); let p1111 = Self::mul(&Self::square(&p101), &p101); - let p11111111 = Self::mul(&Self::pow(&p1111, 16u32), &p1111); - let p111111110000 = Self::pow(&p11111111, 16u32); + let p11111111 = Self::mul(&Self::pow_2(&p1111, 4u32), &p1111); + let p111111110000 = Self::pow_2(&p11111111, 4u32); let p111111111111 = Self::mul(&p111111110000, &p1111); - let p1111111111111111 = Self::mul(&Self::pow(&p111111110000, 16u32), &p11111111); + let p1111111111111111 = Self::mul(&Self::pow_2(&p111111110000, 4u32), &p11111111); let p1111111111111111111111111111 = - Self::mul(&Self::pow(&p1111111111111111, 4096u32), &p111111111111); + Self::mul(&Self::pow_2(&p1111111111111111, 12u32), &p111111111111); let p1111111111111111111111111111101 = - Self::mul(&Self::pow(&p1111111111111111111111111111, 8u32), &p101); + Self::mul(&Self::pow_2(&p1111111111111111111111111111, 3u32), &p101); Ok(p1111111111111111111111111111101) } @@ -120,7 +128,7 @@ impl IsField for Mersenne31Field { } /// Returns the additive neutral element. - fn zero() -> Self::BaseType { + fn zero() -> u32 { 0u32 } @@ -131,16 +139,7 @@ impl IsField for Mersenne31Field { /// Returns the element `x * 1` where 1 is the multiplicative neutral element. fn from_u64(x: u64) -> u32 { - let (lo, hi) = (x as u32 as u64, x >> 32); - // 2^32 = 2 (mod Mersenne 31 bit prime) - // t <= (2^32 - 1) + 2 * (2^32 - 1) = 3 * 2^32 - 3 = 6 * 2^31 - 3 - let t = lo + 2 * hi; - - const MASK: u64 = (1 << 31) - 1; - let (lo, hi) = ((t & MASK) as u32, (t >> 31) as u32); - // 2^31 = 1 mod Mersenne31 - // lo < 2^31, hi < 6, so lo + hi < 2^32. - Self::weak_reduce(lo + hi) + (((((x >> 31) + x + 1) >> 31) + x) & (MERSENNE_31_PRIME_FIELD_ORDER as u64)) as u32 } /// Takes as input an element of BaseType and returns the internal representation @@ -148,6 +147,9 @@ impl IsField for Mersenne31Field { fn from_base_type(x: u32) -> u32 { Self::weak_reduce(x) } + fn double(a: &u32) -> u32 { + Self::weak_reduce(a << 1) + } } impl IsPrimeField for Mersenne31Field { @@ -205,12 +207,45 @@ impl Display for FieldElement { mod tests { use super::*; type F = Mersenne31Field; + type FE = FieldElement; + + #[test] + fn mul_power_two_is_correct() { + let a = 3u32; + let k = 2; + let expected_result = FE::from(&a) * FE::from(2).pow(k as u16); + let result = F::mul_power_two(a, k); + assert_eq!(FE::from(&result), expected_result) + } + + #[test] + fn mul_power_two_is_correct_2() { + let a = 229287u32; + let k = 4; + let expected_result = FE::from(&a) * FE::from(2).pow(k as u16); + let result = F::mul_power_two(a, k); + assert_eq!(FE::from(&result), expected_result) + } + + #[test] + fn pow_2_is_correct() { + let a = 3u32; + let order = 12; + let result = F::pow_2(&a, order); + let expected_result = FE::pow(&FE::from(&a), 4096u32); + assert_eq!(FE::from(&result), expected_result) + } #[test] fn from_hex_for_b_is_11() { assert_eq!(F::from_hex("B").unwrap(), 11); } + #[test] + fn from_hex_for_b_is_11_v2() { + assert_eq!(FE::from_hex("B").unwrap(), FE::from(11)); + } + #[test] fn sum_delayed_reduction() { let up_to = u32::pow(2, 16); @@ -236,190 +271,195 @@ mod tests { #[test] fn one_plus_1_is_2() { - let a = F::one(); - let b = F::one(); - let c = F::add(&a, &b); - assert_eq!(c, 2u32); + assert_eq!(FE::one() + FE::one(), FE::from(&2u32)); } #[test] fn neg_1_plus_1_is_0() { - let a = F::neg(&F::one()); - let b = F::one(); - let c = F::add(&a, &b); - assert_eq!(c, F::zero()); + assert_eq!(-FE::one() + FE::one(), FE::zero()); } #[test] fn neg_1_plus_2_is_1() { - let a = F::neg(&F::one()); - let b = F::from_base_type(2u32); - let c = F::add(&a, &b); - assert_eq!(c, F::one()); + assert_eq!(-FE::one() + FE::from(&2u32), FE::one()); } #[test] fn max_order_plus_1_is_0() { - let a = F::from_base_type(MERSENNE_31_PRIME_FIELD_ORDER - 1); - let b = F::one(); - let c = F::add(&a, &b); - assert_eq!(c, F::zero()); + assert_eq!( + FE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 1)) + FE::from(1), + FE::from(0) + ); } #[test] fn comparing_13_and_13_are_equal() { - let a = F::from_base_type(13); - let b = F::from_base_type(13); - assert_eq!(a, b); + assert_eq!(FE::from(&13u32), FE::from(13)); } #[test] fn comparing_13_and_8_they_are_not_equal() { - let a = F::from_base_type(13); - let b = F::from_base_type(8); - assert_ne!(a, b); + assert_ne!(FE::from(&13u32), FE::from(8)); } #[test] fn one_sub_1_is_0() { - let a = F::one(); - let b = F::one(); - let c = F::sub(&a, &b); - assert_eq!(c, F::zero()); + assert_eq!(FE::one() - FE::one(), FE::zero()); } #[test] fn zero_sub_1_is_order_minus_1() { - let a = F::zero(); - let b = F::one(); - let c = F::sub(&a, &b); - assert_eq!(c, MERSENNE_31_PRIME_FIELD_ORDER - 1); + assert_eq!( + FE::zero() - FE::one(), + FE::from(&(MERSENNE_31_PRIME_FIELD_ORDER - 1)) + ); } #[test] fn neg_1_sub_neg_1_is_0() { - let a = F::neg(&F::one()); - let b = F::neg(&F::one()); - let c = F::sub(&a, &b); - assert_eq!(c, F::zero()); + assert_eq!(-FE::one() - (-FE::one()), FE::zero()); } #[test] - fn neg_1_sub_1_is_neg_1() { - let a = F::neg(&F::one()); - let b = F::zero(); - let c = F::sub(&a, &b); - assert_eq!(c, F::neg(&F::one())); + fn neg_1_sub_0_is_neg_1() { + assert_eq!(-FE::one() - FE::zero(), -FE::one()); } #[test] fn mul_neutral_element() { - let a = F::from_base_type(1); - let b = F::from_base_type(2); - let c = F::mul(&a, &b); - assert_eq!(c, F::from_base_type(2)); + assert_eq!(FE::one() * FE::from(&2u32), FE::from(&2u32)); } #[test] fn mul_2_3_is_6() { - let a = F::from_base_type(2); - let b = F::from_base_type(3); - assert_eq!(a * b, F::from_base_type(6)); + assert_eq!(FE::from(&2u32) * FE::from(&3u32), FE::from(&6u32)); } #[test] fn mul_order_neg_1() { - let a = F::from_base_type(MERSENNE_31_PRIME_FIELD_ORDER - 1); - let b = F::from_base_type(MERSENNE_31_PRIME_FIELD_ORDER - 1); - let c = F::mul(&a, &b); - assert_eq!(c, F::from_base_type(1)); + assert_eq!( + FE::from(MERSENNE_31_PRIME_FIELD_ORDER as u64 - 1) + * FE::from(MERSENNE_31_PRIME_FIELD_ORDER as u64 - 1), + FE::one() + ); } #[test] fn pow_p_neg_1() { assert_eq!( - F::pow(&F::from_base_type(2), MERSENNE_31_PRIME_FIELD_ORDER - 1), - F::one() + FE::pow(&FE::from(&2u32), MERSENNE_31_PRIME_FIELD_ORDER - 1), + FE::one() ) } #[test] fn inv_0_error() { - let result = F::inv(&F::zero()); + let result = FE::inv(&FE::zero()); assert!(matches!(result, Err(FieldError::InvZeroError))); } #[test] fn inv_2() { - let result = F::inv(&F::from_base_type(2u32)).unwrap(); + let result = FE::inv(&FE::from(&2u32)).unwrap(); // sage: 1 / F(2) = 1073741824 - assert_eq!(result, 1073741824); + assert_eq!(result, FE::from(1073741824)); } #[test] fn pow_2_3() { - assert_eq!(F::pow(&F::from_base_type(2), 3_u64), 8) + assert_eq!(FE::pow(&FE::from(&2u32), 3u64), FE::from(8)); } #[test] fn div_1() { - assert_eq!(F::div(&F::from_base_type(2), &F::from_base_type(1)), 2) + assert_eq!(FE::from(&2u32) / FE::from(&1u32), FE::from(&2u32)); } #[test] fn div_4_2() { - assert_eq!(F::div(&F::from_base_type(4), &F::from_base_type(2)), 2) + assert_eq!(FE::from(&4u32) / FE::from(&2u32), FE::from(&2u32)); } - // 1431655766 #[test] fn div_4_3() { // sage: F(4) / F(3) = 1431655766 - assert_eq!( - F::div(&F::from_base_type(4), &F::from_base_type(3)), - 1431655766 - ) + assert_eq!(FE::from(&4u32) / FE::from(&3u32), FE::from(1431655766)); } #[test] fn two_plus_its_additive_inv_is_0() { - let two = F::from_base_type(2); - - assert_eq!(F::add(&two, &F::neg(&two)), F::zero()) + assert_eq!(FE::from(&2u32) + (-FE::from(&2u32)), FE::zero()); } #[test] fn from_u64_test() { - let num = F::from_u64(1u64); - assert_eq!(num, F::one()); + assert_eq!(FE::from(1u64), FE::one()); } #[test] fn creating_a_field_element_from_its_representative_returns_the_same_element_1() { - let change = 1; - let f1 = F::from_base_type(MERSENNE_31_PRIME_FIELD_ORDER + change); - let f2 = F::from_base_type(Mersenne31Field::representative(&f1)); + let change: u32 = MERSENNE_31_PRIME_FIELD_ORDER + 1; + let f1 = FE::from(&change); + let f2 = FE::from(&FE::representative(&f1)); assert_eq!(f1, f2); } #[test] fn creating_a_field_element_from_its_representative_returns_the_same_element_2() { - let change = 8; - let f1 = F::from_base_type(MERSENNE_31_PRIME_FIELD_ORDER + change); - let f2 = F::from_base_type(Mersenne31Field::representative(&f1)); + let change: u32 = MERSENNE_31_PRIME_FIELD_ORDER + 8; + let f1 = FE::from(&change); + let f2 = FE::from(&FE::representative(&f1)); assert_eq!(f1, f2); } #[test] fn from_base_type_test() { - let b = F::from_base_type(1u32); - assert_eq!(b, F::one()); + assert_eq!(FE::from(&1u32), FE::one()); } #[cfg(feature = "std")] #[test] fn to_hex_test() { - let num = F::from_hex("B").unwrap(); - assert_eq!(F::to_hex(&num), "B"); + let num = FE::from_hex("B").unwrap(); + assert_eq!(FE::to_hex(&num), "B"); + } + + #[test] + fn double_equals_add_itself() { + let a = FE::from(1234); + assert_eq!(a + a, a.double()) + } + + #[test] + fn two_square_minus_one_is_correct() { + let a = FE::from(2147483650); + assert_eq!( + FE::from(&F::two_square_minus_one(a.value())), + a.square().double() - FE::one() + ) + } + + #[test] + fn two_square_zero_minus_one_is_minus_one() { + let a = FE::from(0); + assert_eq!( + FE::from(&F::two_square_minus_one(a.value())), + a.square().double() - FE::one() + ) + } + + #[test] + fn two_square_p_minus_one_is_minus_one() { + let a = FE::from(&MERSENNE_31_PRIME_FIELD_ORDER); + assert_eq!( + FE::from(&F::two_square_minus_one(a.value())), + a.square().double() - FE::one() + ) + } + + #[test] + fn mul_by_inv() { + let x = 3476715743_u32; + assert_eq!(FE::from(&x).inv().unwrap() * FE::from(&x), FE::one()); } } diff --git a/math/src/field/fields/mersenne31/mod.rs b/math/src/field/fields/mersenne31/mod.rs index 4bfd3daf1..2272e7d5e 100644 --- a/math/src/field/fields/mersenne31/mod.rs +++ b/math/src/field/fields/mersenne31/mod.rs @@ -1,2 +1,2 @@ -pub mod extension; +pub mod extensions; pub mod field; diff --git a/math/src/field/fields/p448_goldilocks_prime_field.rs b/math/src/field/fields/p448_goldilocks_prime_field.rs index 9f67fd1d2..eadd61541 100644 --- a/math/src/field/fields/p448_goldilocks_prime_field.rs +++ b/math/src/field/fields/p448_goldilocks_prime_field.rs @@ -16,7 +16,7 @@ pub const P448_GOLDILOCKS_PRIME_FIELD_ORDER: U448 = /// 448-bit unsigned integer represented as /// a size 8 `u64` array `limbs` of 56-bit words. /// The least significant word is in the left most position. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct U56x8 { limbs: [u64; 8], } diff --git a/math/src/field/traits.rs b/math/src/field/traits.rs index a9a39d2dd..320531f42 100644 --- a/math/src/field/traits.rs +++ b/math/src/field/traits.rs @@ -99,9 +99,9 @@ pub trait IsField: Debug + Clone { /// The underlying base type for representing elements from the field. // TODO: Relax Unpin for non cuda usage #[cfg(feature = "lambdaworks-serde-binary")] - type BaseType: Clone + Debug + Unpin + ByteConversion; + type BaseType: Clone + Debug + Unpin + ByteConversion + Default; #[cfg(not(feature = "lambdaworks-serde-binary"))] - type BaseType: Clone + Debug + Unpin; + type BaseType: Clone + Debug + Unpin + Default; /// Returns the sum of `a` and `b`. fn add(a: &Self::BaseType, b: &Self::BaseType) -> Self::BaseType; @@ -173,7 +173,9 @@ pub trait IsField: Debug + Clone { fn eq(a: &Self::BaseType, b: &Self::BaseType) -> bool; /// Returns the additive neutral element. - fn zero() -> Self::BaseType; + fn zero() -> Self::BaseType { + Self::BaseType::default() + } /// Returns the multiplicative neutral element. fn one() -> Self::BaseType; diff --git a/math/src/polynomial/mod.rs b/math/src/polynomial/mod.rs index 8a0671776..ee27923d0 100644 --- a/math/src/polynomial/mod.rs +++ b/math/src/polynomial/mod.rs @@ -192,6 +192,36 @@ impl Polynomial> { } } + /// Extended Euclidean Algorithm for polynomials. + /// + /// This method computes the extended greatest common divisor (GCD) of two polynomials `self` and `y`. + /// It returns a tuple of three elements: `(a, b, g)` such that `a * self + b * y = g`, where `g` is the + /// greatest common divisor of `self` and `y`. + pub fn xgcd(&self, y: &Self) -> (Self, Self, Self) { + let one = Polynomial::new(&[FieldElement::one()]); + let zero = Polynomial::zero(); + let (mut old_r, mut r) = (self.clone(), y.clone()); + let (mut old_s, mut s) = (one.clone(), zero.clone()); + let (mut old_t, mut t) = (zero.clone(), one.clone()); + + while r != Polynomial::zero() { + let quotient = old_r.clone().div_with_ref(&r); + old_r = old_r - "ient * &r; + core::mem::swap(&mut old_r, &mut r); + old_s = old_s - "ient * &s; + core::mem::swap(&mut old_s, &mut s); + old_t = old_t - "ient * &t; + core::mem::swap(&mut old_t, &mut t); + } + + let lcinv = old_r.leading_coefficient().inv().unwrap(); + ( + old_s.scale_coeffs(&lcinv), + old_t.scale_coeffs(&lcinv), + old_r.scale_coeffs(&lcinv), + ) + } + pub fn div_with_ref(self, dividend: &Self) -> Self { let (quotient, _remainder) = self.long_division_with_remainder(dividend); quotient @@ -1122,4 +1152,29 @@ mod tests { prop_assert_eq!(q, p); } } + #[test] + fn test_xgcd() { + // Case 1: Simple polynomials + let p1 = Polynomial::new(&[FE::new(1), FE::new(0), FE::new(1)]); // x^2 + 1 + let p2 = Polynomial::new(&[FE::new(1), FE::new(1)]); // x + 1 + let (a, b, g) = p1.xgcd(&p2); + // Check that a * p1 + b * p2 = g + let lhs = a.mul_with_ref(&p1) + b.mul_with_ref(&p2); + assert_eq!(a, Polynomial::new(&[FE::new(12)])); + assert_eq!(b, Polynomial::new(&[FE::new(12), FE::new(11)])); + assert_eq!(lhs, g); + assert_eq!(g, Polynomial::new(&[FE::new(1)])); + + // x^2-1 : + let p3 = Polynomial::new(&[FE::new(ORDER - 1), FE::new(0), FE::new(1)]); + // x^3-x = x(x^2-1) + let p4 = Polynomial::new(&[FE::new(0), FE::new(ORDER - 1), FE::new(0), FE::new(1)]); + let (a, b, g) = p3.xgcd(&p4); + + let lhs = a.mul_with_ref(&p3) + b.mul_with_ref(&p4); + assert_eq!(a, Polynomial::new(&[FE::new(1)])); + assert_eq!(b, Polynomial::zero()); + assert_eq!(lhs, g); + assert_eq!(g, p3); + } } diff --git a/math/src/unsigned_integer/element.rs b/math/src/unsigned_integer/element.rs index 021afd9a3..1613e192b 100644 --- a/math/src/unsigned_integer/element.rs +++ b/math/src/unsigned_integer/element.rs @@ -36,6 +36,14 @@ pub struct UnsignedInteger { pub limbs: [u64; NUM_LIMBS], } +impl Default for UnsignedInteger { + fn default() -> Self { + Self { + limbs: [0; NUM_LIMBS], + } + } +} + // NOTE: manually implementing `PartialOrd` may seem unorthodox, but the // derived implementation had terrible performance. #[allow(clippy::non_canonical_partial_ord_impl)] diff --git a/provers/README.md b/provers/README.md index 4ab43c974..bca05a49a 100644 --- a/provers/README.md +++ b/provers/README.md @@ -6,7 +6,7 @@ This folder contains the different provers currently supported by lambdaworks: - [Groth 16](https://github.com/lambdaclass/lambdaworks/tree/main/provers/groth16) - [Plonk](https://github.com/lambdaclass/lambdaworks/tree/main/provers/plonk) - [STARKs](https://github.com/lambdaclass/lambdaworks/tree/main/provers/stark) -- [Cairo](https://github.com/lambdaclass/lambdaworks/tree/main/provers/cairo) +- [Cairo](https://github.com/lambdaclass/lambdaworks/tree/a591186e6c4dd53301b03b4ddd69369abe99f960/provers/cairo) - This is only for learning purposes and no longer supported. The [docs](../docs/src/starks/) still contain information that could be useful to understand and learn how Cairo works. The reference papers for each of the provers is given below: - [Groth 16](https://eprint.iacr.org/2016/260) @@ -22,5 +22,4 @@ Using one prover or another depends on usecase and other desired properties. We ## Using provers -- [Cairo prover](https://github.com/lambdaclass/lambdaworks/blob/main/provers/cairo/README.md) - [Plonk prover](https://github.com/lambdaclass/lambdaworks/blob/main/provers/plonk/README.md) diff --git a/provers/cairo/Cargo.toml b/provers/cairo/Cargo.toml deleted file mode 100644 index bdc4829ec..000000000 --- a/provers/cairo/Cargo.toml +++ /dev/null @@ -1,121 +0,0 @@ -[package] -name = "cairo-platinum-prover" -rust-version = "1.66" -version.workspace = true -edition.workspace = true -license.workspace = true - -[[bin]] -name = "platinum-prover" -path = "src/main.rs" -required-features = ["cli"] - -[lib] -name = "cairo_platinum_prover" -crate-type = ["cdylib", "rlib"] - -[dependencies] -rand = "0.8.5" -lambdaworks-math = { workspace = true, default-features = true, features = ["lambdaworks-serde-binary"] } -lambdaworks-crypto = { workspace = true, default-features = true } -stark-platinum-prover = { workspace = true, features = ["wasm"] } -thiserror = "1.0.38" -log = "0.4.17" -bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git", features= ['serde'] } -# NOTE: For cairo 1 compatibility, add the `cairo-1-hints` feature. -cairo-vm = { git = "https://github.com/lambdaclass/cairo-vm", rev = "e61ae177edb94e29470fed23bdda43329b16c057", default-features = false } -sha3 = "0.10.6" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -num-integer = "0.1.45" -itertools = "0.11.0" -serde_cbor = { version = "0.11.1" } -# For cli -clap = { version = "4.4.6", features = ["derive"], optional = true } -# Parallelization crates -rayon = { version = "1.8.0", optional = true } - -# wasm -wasm-bindgen = { version = "0.2", optional = true } -serde-wasm-bindgen = { version = "0.5", optional = true } -web-sys = { version = "0.3.64", features = ['console'], optional = true } - -[dev-dependencies] -hex = "0.4.3" -criterion = { version = "0.4", default-features = false } -env_logger = "*" -test-log = { version = "0.2.11", features = ["log"] } -assert_matches = "1.5.0" -rstest = "0.17.0" -rand = "0.8.5" -wasm-bindgen-test = "0.3.0" - -[features] -test_fiat_shamir = [] -instruments = ["stark-platinum-prover/instruments"]# This enables timing prints in prover and verifier -metal = ["lambdaworks-math/metal"] -parallel = ["dep:rayon", "stark-platinum-prover/parallel"] -wasm = ["dep:wasm-bindgen", "dep:serde-wasm-bindgen", "dep:web-sys"] -cli = ["dep:clap"] -[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dev-dependencies] -proptest = "1.2.0" - -[[bench]] -name = "criterion_prover" -harness = false -metal = ["lambdaworks-math/metal"] - -[[bench]] -name = "criterion_prover_70k" -harness = false -metal = ["lambdaworks-math/metal"] - -[[bench]] -name = "criterion_verifier" -harness = false -metal = ["lambdaworks-math/metal"] - -[[bench]] -name = "criterion_verifier_70k" -harness = false - -[package.metadata.wasm-pack.profile.dev] -# Should `wasm-opt` be used to further optimize the wasm binary generated after -# the Rust compiler has finished? Using `wasm-opt` can often further decrease -# binary size or do clever tricks that haven't made their way into LLVM yet. -# -# Configuration is set to `false` by default for the dev profile, but it can -# be set to an array of strings which are explicit arguments to pass to -# `wasm-opt`. For example `['-Os']` would optimize for size while `['-O4']` -# would execute very expensive optimizations passes -wasm-opt = ['-O'] - -[package.metadata.wasm-pack.profile.dev.wasm-bindgen] -# Should we enable wasm-bindgen's debug assertions in its generated JS glue? -debug-js-glue = true -# Should wasm-bindgen demangle the symbols in the "name" custom section -demangle-name-section = true -# Should we emit the DWARF debug info custom sections -dwarf-debug-info = false -# Should we omit the default import path -omit-default-module-path = false - -[package.metadata.wasm-pack.profile.profiling] -wasm-opt = ['-O'] - -[package.metadata.wasm-pack.profile.profiling.wasm-bindgen] -debug-js-glue = false -demangle-name-section = true -dwarf-debug-info = false -omit-default-module-path = false - -# `wasm-opt` is on by default in for the release profile, but it can be -# disabled by setting it to `false` -[package.metadata.wasm-pack.profile.release] -wasm-opt = false - -[package.metadata.wasm-pack.profile.release.wasm-bindgen] -debug-js-glue = false -demangle-name-section = true -dwarf-debug-info = false -omit-default-module-path = false diff --git a/provers/cairo/Makefile b/provers/cairo/Makefile deleted file mode 100644 index 3242e95da..000000000 --- a/provers/cairo/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -.PHONY: test coverage clippy clean - -ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) - -CAIRO0_PROGRAMS_DIR=cairo_programs/cairo0 -CAIRO0_PROGRAMS:=$(wildcard $(CAIRO0_PROGRAMS_DIR)/*.cairo) -COMPILED_CAIRO0_PROGRAMS:=$(patsubst $(CAIRO0_PROGRAMS_DIR)/%.cairo, $(CAIRO0_PROGRAMS_DIR)/%.json, $(CAIRO0_PROGRAMS)) - -# Variable to give compiled Cairo programas a proper name. It extracts the file extension and adds -# the .json extension to it. -COMPILED_PROGRAM=$(basename $(PROGRAM)).json - -# Rule to compile Cairo programs for testing purposes. -# If the `cairo-lang` toolchain is installed, programs will be compiled with it. -# Otherwise, the cairo_compile docker image will be used -# When using the docker version, be sure to build the image using `make docker_build_cairo_compiler`. -$(CAIRO0_PROGRAMS_DIR)/%.json: $(CAIRO0_PROGRAMS_DIR)/%.cairo - @echo "Compiling Cairo program..." - @cairo-compile --cairo_path="$(CAIRO0_PROGRAMS_DIR)" $< --output $@ 2> /dev/null --proof_mode || \ - docker run --rm -v $(ROOT_DIR)/$(CAIRO0_PROGRAMS_DIR):/pwd/$(CAIRO0_PROGRAMS_DIR) cairo --proof_mode /pwd/$< > $@ - -build: - cargo build --release - -test: $(COMPILED_CAIRO0_PROGRAMS) - cargo test - -test_metal: $(COMPILED_CAIRO0_PROGRAMS) - cargo test -F metal - -docker_build_cairo_compiler: - docker build -f cairo_compile.Dockerfile -t cairo . - -docker_compile_cairo: - docker run -v $(ROOT_DIR):/pwd cairo --proof_mode /pwd/$(PROGRAM) > $(COMPILED_PROGRAM) - -clippy: - cargo clippy --workspace --all-targets -- -D warnings - -benchmarks_sequential: $(COMPILED_CAIRO0_PROGRAMS) - cargo bench - -benchmarks_parallel: $(COMPILED_CAIRO0_PROGRAMS) - cargo bench -F parallel --bench criterion_prover - cargo bench -F parallel --bench criterion_verifier - -benchmarks_parallel_all: $(COMPILED_CAIRO0_PROGRAMS) - cargo bench -F parallel - -build_metal: - cargo b --features metal --release - -clean: - rm -f $(CAIRO0_PROGRAMS_DIR)/*.json - rm -f $(CAIRO0_PROGRAMS_DIR)/*.proof - rm -f $(CAIRO0_PROGRAMS_DIR)/*.trace - rm -f $(CAIRO0_PROGRAMS_DIR)/*.memory - -build_wasm: - wasm-pack build --target=web -- --features wasm - -test_wasm: - wasm-pack test --node --release -- --features wasm diff --git a/provers/cairo/README.md b/provers/cairo/README.md deleted file mode 100644 index e4651568c..000000000 --- a/provers/cairo/README.md +++ /dev/null @@ -1,223 +0,0 @@ -
- -# Lambdaworks Cairo Platinum Prover CLI - -
- -## ⚠️ Disclaimer - -This prover is still in development and may contain bugs. It is not intended to be used in production yet. - -Please check issues under security label, and wait for them to be resolved if they are relevant to your project. - -## [Cairo Platinum Prover Docs](https://lambdaclass.github.io/lambdaworks/starks/cairo.html) - -## Proof file - -Currently, the .proof file contains the following elements concatenated: -- Proof size -- Proof -- Public inputs - -It uses the bincode as protocol to encode the structs of the files. Fields are stored as the bytes of canonical non-Montgomery form. It is in full big-endian form. Limbs are ordered in big-endian, and each u64 of the Montgomery field is in big-endian. - -⚠️: There may be changes to how this file represents the proof, always check here to ensure you have the latest encoding. We will add presets of verifications to the public inputs so you should not need to handle the file, just enable them. - -### Cairo Platinum Prover - Introduction - -Cairo Platinum Prover is an easy to use prover to prove CairoZero and Cairo programs, with support for a web verifier. - -CLI currently runs with 100 bits of conjecturable security. - -Cairo / Cairo1 programs full integration is on the way. It can already be used generating a trace and a memory with the Cairo VM Runner, and fed to the prover with the prove command. - -For using Cairo1, use the following [VM version](https://github.com/lambdaclass/cairo-vm/commit/070aeb9dbaf55875bf1cba2cef36fccafbb4851a) until it gets fixed in main - -Notice in this version you don't need the flag ```--proof_mode``` as it's enabled by default. - -### Usage: - -To prove Cairo programs, they first need to be compiled. For compilation you need to have `cairo-lang` or `docker` installed. - -When using Docker, start by creating the container image with: - -```**bash** - make docker_build_cairo_compiler -``` - -Examples of Cairo 0 programs can be found [here](https://github.com/lambdaclass/lambdaworks/tree/main/provers/cairo/cairo-prover-lib/cairo_programs/cairo0) - - -**To compile and generate a proof you can use:** - -```bash -cargo run --release --features=cli,instruments,parallel compile-and-prove -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel compile-and-prove cairo_programs/cairo0/fibonacci_5.cairo cairo_programs/cairo0/fibonacci_5.proof -``` - - -**To verify a proof you can use:** - -```bash -cargo run --release --features=cli,instruments,parallel verify -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel verify cairo_programs/cairo0/fibonacci_5.proof -``` - -**To compile Cairo:** - -```bash -cargo run --release --features=cli,instruments,parallel compile -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel compile cairo_programs/cairo0/fibonacci_5.cairo -``` - -**To execute and prove a compiled program:** - -```bash -cargo run --release --features=cli,instruments,parallel run-and-prove -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel run-and-prove cairo_programs/cairo0/fibonacci_5.json program_proof.proof -``` - -**To prove a trace of a cairo program:** - -```bash -cargo run --release --features=cli,instruments,parallel prove -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel prove cairo_programs/cairo0/fibonacci_5_trace.bin cairo_programs/cairo0/fibonacci_5_memory.bin program_proof.proof -``` - -**To prove and verify with a single command you can use:** - -```bash -cargo run --release --features=cli,instruments,parallel prove-and-verify -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel prove-and-verify cairo_programs/cairo0/fibonacci_5.json -``` - - - -**To compile, proof, prove and verify at the same time you can use:** - -```bash -cargo run --release --features=cli,instruments,parallel compile-prove-and-verify -``` - -For example: - -```bash -cargo run --release --features=cli,instruments,parallel compile-prove-and-verify cairo_programs/cairo0/fibonacci_5.cairo -``` - -### Build Package for web verifier - -To build the node library to use the verifier on the browser, use `build_wasm`. Using as proof options the ones that match the CLI, or your configuration, you can send the proof to the exposed function and verify it seamlessly. - -### Run CLI as a binary - -**To install as a binary run the command on the root directory of the CLI:** -```bash -cargo install --features=cli,instruments,parallel --path . -``` - -To run the CLI as a binary instead of using cargo replace `cargo run --release --features=cli,instruments,parallel` with `platinum-prover`. - -for example, the command to generate a proof becomes: -```bash -platinum-prover prove cairo_programs/cairo0/fibonacci_5.json cairo_programs/cairo0/fibonacci_5.proof -``` - -**You can uninstall the binary with:** -```bash -cargo uninstall -``` - -## Running tests -To run tests, simply use -``` -make test -``` -If you have the `cairo-lang` toolchain installed, this will compile the Cairo programs needed -for tests. -If you have built the cairo-compile docker image, that will be used for compiling instead. - -Be sure to build the docker image if you don't want to install the `cairo-lang` toolchain: -``` -make docker_build_cairo_compiler -``` - -## To be added -- Stone compatibility -- Add program as a public input -- Add Cairo compilation inside Rust, to prove and verify Cairo1/Cairo2 from the .cairo file, instead of the .casm file -- Add more Layouts / Builtins -- Improve parallelization -- Benchmarks and optimizations for Graviton -- Cairo Verifier - - Batch verifier / For trees and N proofs -- Pick hash configuration with ProofOptions - -## πŸ“š References - -The following links, repos and projects have been important in the development of this library and we want to thank and acknowledge them. - -- [Starkware](https://starkware.co/) -- [Winterfell](https://github.com/facebook/winterfell) -- [Anatomy of a Stark](https://aszepieniec.github.io/stark-anatomy/overview) -- [Giza](https://github.com/maxgillett/giza) -- [Ministark](https://github.com/andrewmilson/ministark) -- [Sandstorm](https://github.com/andrewmilson/sandstorm) -- [STARK-101](https://starkware.co/stark-101/) -- [Risc0](https://github.com/risc0/risc0) -- [Neptune](https://github.com/Neptune-Crypto) -- [Summary on FRI low degree test](https://eprint.iacr.org/2022/1216) -- [STARKs paper](https://eprint.iacr.org/2018/046) -- [DEEP FRI](https://eprint.iacr.org/2019/336) -- [BrainSTARK](https://aszepieniec.github.io/stark-brainfuck/) -- [Plonky2](https://github.com/mir-protocol/plonky2) -- [Aztec](https://github.com/AztecProtocol) -- [Arkworks](https://github.com/arkworks-rs) -- [Thank goodness it's FRIday](https://vitalik.ca/general/2017/11/22/starks_part_2.html) -- [Diving DEEP FRI](https://blog.lambdaclass.com/diving-deep-fri/) -- [Periodic constraints](https://blog.lambdaclass.com/periodic-constraints-and-recursion-in-zk-starks/) -- [Chiplets Miden VM](https://wiki.polygon.technology/docs/miden/design/chiplets/main/) -- [Valida](https://github.com/valida-xyz/valida/tree/main) -- [Solidity Verifier](https://github.com/starkware-libs/starkex-contracts/tree/master/evm-verifier/solidity/contracts/cpu) -- [CAIRO verifier](https://github.com/starkware-libs/cairo-lang/tree/master/src/starkware/cairo/stark_verifier) -- [EthSTARK](https://github.com/starkware-libs/ethSTARK/tree/master) -- [CAIRO whitepaper](https://eprint.iacr.org/2021/1063.pdf) -- [Gnark](https://github.com/Consensys/gnark) - -## 🌞 Related Projects - -- [CAIRO VM - Rust](https://github.com/lambdaclass/cairo-vm) -- [CAIRO VM - Go](https://github.com/lambdaclass/cairo_vm.go) -- [CAIRO native](https://github.com/lambdaclass/cairo_native/) -- [StarkNet in Rust](https://github.com/lambdaclass/starknet_in_rust) -- [StarkNet Stack](https://github.com/lambdaclass/starknet_stack) diff --git a/provers/cairo/benches/criterion_prover.rs b/provers/cairo/benches/criterion_prover.rs deleted file mode 100644 index 7a8e91308..000000000 --- a/provers/cairo/benches/criterion_prover.rs +++ /dev/null @@ -1,67 +0,0 @@ -use cairo_platinum_prover::{ - air::generate_cairo_proof, cairo_layout::CairoLayout, runner::run::generate_prover_args, -}; -use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, -}; -use stark_platinum_prover::proof::options::{ProofOptions, SecurityLevel}; - -pub mod functions; - -fn cairo_benches(c: &mut Criterion) { - #[cfg(feature = "parallel")] - { - let num_threads: usize = std::env::var("NUM_THREADS") - .unwrap_or("8".to_string()) - .parse() - .unwrap(); - println!("Running benchmarks using {} threads", num_threads); - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - }; - - let mut group = c.benchmark_group("CAIRO"); - group.sample_size(10); - run_cairo_bench( - &mut group, - "fibonacci/500", - &cairo0_program_path("fibonacci_500.json"), - CairoLayout::Plain, - ); - run_cairo_bench( - &mut group, - "fibonacci/1000", - &cairo0_program_path("fibonacci_1000.json"), - CairoLayout::Plain, - ); -} - -fn cairo0_program_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const PROGRAM_BASE_REL_PATH: &str = "/cairo_programs/cairo0/"; - let program_base_path = CARGO_DIR.to_string() + PROGRAM_BASE_REL_PATH; - program_base_path + program_name -} - -fn run_cairo_bench( - group: &mut BenchmarkGroup<'_, WallTime>, - benchname: &str, - program_path: &str, - layout: CairoLayout, -) { - let program_content = std::fs::read(program_path).unwrap(); - let proof_options = ProofOptions::new_secure(SecurityLevel::Provable80Bits, 3); - let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap(); - println!("Generated main trace with {} rows", main_trace.n_rows()); - - group.bench_function(benchname, |bench| { - bench.iter(|| { - black_box(generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap()) - }); - }); -} - -criterion_group!(benches, cairo_benches); -criterion_main!(benches); diff --git a/provers/cairo/benches/criterion_prover_70k.rs b/provers/cairo/benches/criterion_prover_70k.rs deleted file mode 100644 index 31f73e3a1..000000000 --- a/provers/cairo/benches/criterion_prover_70k.rs +++ /dev/null @@ -1,61 +0,0 @@ -use cairo_platinum_prover::cairo_layout::CairoLayout; -use cairo_platinum_prover::{air::generate_cairo_proof, runner::run::generate_prover_args}; -use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, - SamplingMode, -}; -use stark_platinum_prover::proof::options::{ProofOptions, SecurityLevel}; - -pub mod functions; - -fn fibo_70k_bench(c: &mut Criterion) { - #[cfg(feature = "parallel")] - { - let num_threads: usize = std::env::var("NUM_THREADS") - .unwrap_or("8".to_string()) - .parse() - .unwrap(); - println!("Running benchmarks using {} threads", num_threads); - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - }; - - let mut group = c.benchmark_group("CAIRO"); - group.sampling_mode(SamplingMode::Flat); - group.sample_size(10); - run_cairo_bench( - &mut group, - "fibonacci/70000", - &cairo0_program_path("fibonacci_70000.json"), - CairoLayout::Plain, - ); -} - -fn cairo0_program_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const PROGRAM_BASE_REL_PATH: &str = "/cairo_programs/cairo0/"; - let program_base_path = CARGO_DIR.to_string() + PROGRAM_BASE_REL_PATH; - program_base_path + program_name -} - -fn run_cairo_bench( - group: &mut BenchmarkGroup<'_, WallTime>, - benchname: &str, - program_path: &str, - layout: CairoLayout, -) { - let program_content = std::fs::read(program_path).unwrap(); - let proof_options = ProofOptions::new_secure(SecurityLevel::Provable80Bits, 3); - let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap(); - - group.bench_function(benchname, |bench| { - bench.iter(|| { - black_box(generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap()) - }); - }); -} - -criterion_group!(benches, fibo_70k_bench); -criterion_main!(benches); diff --git a/provers/cairo/benches/criterion_verifier.rs b/provers/cairo/benches/criterion_verifier.rs deleted file mode 100644 index f4a82c957..000000000 --- a/provers/cairo/benches/criterion_verifier.rs +++ /dev/null @@ -1,87 +0,0 @@ -use cairo_platinum_prover::air::{verify_cairo_proof, PublicInputs}; -use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, -}; -use lambdaworks_math::{ - field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::Deserializable, -}; -use stark_platinum_prover::proof::{ - options::{ProofOptions, SecurityLevel}, - stark::StarkProof, -}; - -pub mod functions; - -fn load_proof_and_pub_inputs( - input_path: &str, -) -> ( - StarkProof, - PublicInputs, -) { - let program_content = std::fs::read(input_path).unwrap(); - let mut bytes = program_content.as_slice(); - let proof_len = usize::from_be_bytes(bytes[0..8].try_into().unwrap()); - bytes = &bytes[8..]; - let proof: StarkProof = - serde_cbor::from_slice(&bytes[0..proof_len]).unwrap(); - bytes = &bytes[proof_len..]; - - let public_inputs = PublicInputs::deserialize(bytes).unwrap(); - - (proof, public_inputs) -} - -fn verifier_benches(c: &mut Criterion) { - #[cfg(feature = "parallel")] - { - let num_threads: usize = std::env::var("NUM_THREADS") - .unwrap_or("8".to_string()) - .parse() - .unwrap(); - println!("Running benchmarks using {} threads", num_threads); - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - }; - - let mut group = c.benchmark_group("VERIFIER"); - run_verifier_bench( - &mut group, - "fibonacci/500", - &cairo0_proof_path("fibonacci_500.proof"), - ); - run_verifier_bench( - &mut group, - "fibonacci/1000", - &cairo0_proof_path("fibonacci_1000.proof"), - ); -} - -fn cairo0_proof_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const PROGRAM_BASE_REL_PATH: &str = "/benches/proofs/"; - let program_base_path = CARGO_DIR.to_string() + PROGRAM_BASE_REL_PATH; - program_base_path + program_name -} - -fn run_verifier_bench( - group: &mut BenchmarkGroup<'_, WallTime>, - benchname: &str, - program_path: &str, -) { - let (proof, pub_inputs) = load_proof_and_pub_inputs(program_path); - let proof_options = ProofOptions::new_secure(SecurityLevel::Conjecturable80Bits, 3); - group.bench_function(benchname, |bench| { - bench.iter(|| { - assert!(black_box(verify_cairo_proof( - &proof, - &pub_inputs, - &proof_options - ))) - }); - }); -} - -criterion_group!(benches, verifier_benches); -criterion_main!(benches); diff --git a/provers/cairo/benches/criterion_verifier_70k.rs b/provers/cairo/benches/criterion_verifier_70k.rs deleted file mode 100644 index 6597d56e3..000000000 --- a/provers/cairo/benches/criterion_verifier_70k.rs +++ /dev/null @@ -1,79 +0,0 @@ -use cairo_platinum_prover::air::{verify_cairo_proof, PublicInputs}; -use criterion::{ - black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, Criterion, - SamplingMode, -}; -use lambdaworks_math::{ - field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, traits::Deserializable, -}; -use stark_platinum_prover::proof::{ - options::{ProofOptions, SecurityLevel}, - stark::StarkProof, -}; - -pub mod functions; - -fn load_proof_and_pub_inputs( - input_path: &str, -) -> ( - StarkProof, - PublicInputs, -) { - let program_content = std::fs::read(input_path).unwrap(); - let mut bytes = program_content.as_slice(); - let proof_len = usize::from_be_bytes(bytes[0..8].try_into().unwrap()); - bytes = &bytes[8..]; - let proof: StarkProof = - serde_cbor::from_slice(&bytes[0..proof_len]).unwrap(); - bytes = &bytes[proof_len..]; - - let public_inputs = PublicInputs::deserialize(bytes).unwrap(); - - (proof, public_inputs) -} - -fn verifier_benches(c: &mut Criterion) { - #[cfg(feature = "parallel")] - { - let num_threads: usize = std::env::var("NUM_THREADS") - .unwrap_or("8".to_string()) - .parse() - .unwrap(); - println!("Running benchmarks using {} threads", num_threads); - rayon::ThreadPoolBuilder::new() - .num_threads(num_threads) - .build_global() - .unwrap(); - }; - - let mut group = c.benchmark_group("VERIFIER"); - group.sampling_mode(SamplingMode::Flat); - group.sample_size(10); - run_verifier_bench( - &mut group, - "fibonacci/70000", - &cairo0_proof_path("fibonacci_70000.proof"), - ); -} - -fn cairo0_proof_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const PROGRAM_BASE_REL_PATH: &str = "/benches/proofs/"; - let program_base_path = CARGO_DIR.to_string() + PROGRAM_BASE_REL_PATH; - program_base_path + program_name -} - -fn run_verifier_bench( - group: &mut BenchmarkGroup<'_, WallTime>, - benchname: &str, - program_path: &str, -) { - let (proof, pub_inputs) = load_proof_and_pub_inputs(program_path); - let proof_options = ProofOptions::new_secure(SecurityLevel::Provable80Bits, 3); - group.bench_function(benchname, |bench| { - bench.iter(|| black_box(verify_cairo_proof(&proof, &pub_inputs, &proof_options))); - }); -} - -criterion_group!(benches, verifier_benches); -criterion_main!(benches); diff --git a/provers/cairo/benches/functions/cairo.rs b/provers/cairo/benches/functions/cairo.rs deleted file mode 100644 index fe7e4f1e4..000000000 --- a/provers/cairo/benches/functions/cairo.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub fn cairo0_program_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const PROGRAM_BASE_REL_PATH: &str = "/cairo_programs/cairo0/"; - let program_base_path = CARGO_DIR.to_string() + PROGRAM_BASE_REL_PATH; - program_base_path + program_name -} diff --git a/provers/cairo/benches/functions/mod.rs b/provers/cairo/benches/functions/mod.rs deleted file mode 100644 index c3514ea0b..000000000 --- a/provers/cairo/benches/functions/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod cairo; -pub mod stark; diff --git a/provers/cairo/benches/functions/stark.rs b/provers/cairo/benches/functions/stark.rs deleted file mode 100644 index 15f461148..000000000 --- a/provers/cairo/benches/functions/stark.rs +++ /dev/null @@ -1,14 +0,0 @@ -use cairo_platinum_prover::{cairo_mem::CairoMemory, register_states::RegisterStates}; - -pub fn generate_cairo_trace(filename: &str) -> (RegisterStates, CairoMemory) { - let base_dir = env!("CARGO_MANIFEST_DIR").to_string() + "/src/cairo_vm/test_data/"; - - let trace_path = format!("{base_dir}/{filename}.trace"); - let memory_path = format!("{base_dir}/{filename}.memory"); - - let register_states = - RegisterStates::from_file(&trace_path).expect("Cairo trace binary file not found"); - let memory = CairoMemory::from_file(&memory_path).expect("Cairo memory binary file not found"); - - (register_states, memory) -} diff --git a/provers/cairo/benches/proofs/fibonacci_1000.proof b/provers/cairo/benches/proofs/fibonacci_1000.proof deleted file mode 100644 index 338dce624..000000000 Binary files a/provers/cairo/benches/proofs/fibonacci_1000.proof and /dev/null differ diff --git a/provers/cairo/benches/proofs/fibonacci_500.proof b/provers/cairo/benches/proofs/fibonacci_500.proof deleted file mode 100644 index d297fae15..000000000 Binary files a/provers/cairo/benches/proofs/fibonacci_500.proof and /dev/null differ diff --git a/provers/cairo/benches/proofs/fibonacci_70000.proof b/provers/cairo/benches/proofs/fibonacci_70000.proof deleted file mode 100644 index 99813bb88..000000000 Binary files a/provers/cairo/benches/proofs/fibonacci_70000.proof and /dev/null differ diff --git a/provers/cairo/cairo_compile.Dockerfile b/provers/cairo/cairo_compile.Dockerfile deleted file mode 100644 index 369f6db84..000000000 --- a/provers/cairo/cairo_compile.Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.9-slim - -WORKDIR /app - -RUN apt-get update && apt-get install -y --no-install-recommends g++ libgmp3-dev - -COPY requirements.txt / - -RUN pip install -r /requirements.txt - -ENTRYPOINT ["cairo-compile"] diff --git a/provers/cairo/cairo_programs/cairo0/.gitignore b/provers/cairo/cairo_programs/cairo0/.gitignore deleted file mode 100644 index c58f635e1..000000000 --- a/provers/cairo/cairo_programs/cairo0/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.json -*.proof diff --git a/provers/cairo/cairo_programs/cairo0/call_func.cairo b/provers/cairo/cairo_programs/cairo0/call_func.cairo deleted file mode 100644 index 1cd360ba6..000000000 --- a/provers/cairo/cairo_programs/cairo0/call_func.cairo +++ /dev/null @@ -1,13 +0,0 @@ -func mul(x: felt, y: felt) -> (res: felt) { - return (res = x * y); -} - -func main() { - let x = 2; - let y = 3; - - let (res) = mul(x, y); - assert res = 6; - - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/compare_lesser_array.cairo b/provers/cairo/cairo_programs/cairo0/compare_lesser_array.cairo deleted file mode 100644 index 78d3ca454..000000000 --- a/provers/cairo/cairo_programs/cairo0/compare_lesser_array.cairo +++ /dev/null @@ -1,39 +0,0 @@ -%builtins range_check - -from starkware.cairo.common.bool import TRUE, FALSE -from starkware.cairo.common.alloc import alloc -from starkware.cairo.common.math_cmp import is_le - -// Returns TRUE is array_a is lesser than array_b, which means every element in a is lesser than every element in b -func compare_lesser_array{range_check_ptr: felt}( - array_a: felt*, array_b: felt*, array_length: felt, iterator: felt -) -> (r: felt) { - if (iterator == array_length) { - return (TRUE,); - } - let comparison = is_le(array_a[iterator], array_b[iterator]); - if (comparison == FALSE) { - return (FALSE,); - } - return compare_lesser_array(array_a, array_b, array_length, iterator + 1); -} - -func fill_array(array: felt*, base: felt, step: felt, array_length: felt, iterator: felt) { - if (iterator == array_length) { - return (); - } - assert array[iterator] = base + step * iterator; - return fill_array(array, base, step, array_length, iterator + 1); -} - -func main{range_check_ptr: felt}() { - alloc_locals; - tempvar array_length = 10; - let (array_a: felt*) = alloc(); - let (array_b: felt*) = alloc(); - fill_array(array_a, 5, 2, array_length, 0); - fill_array(array_b, 7, 3, array_length, 0); - let result: felt = compare_lesser_array(array_a, array_b, array_length, 0); - assert result = TRUE; - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_10.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_10.cairo deleted file mode 100644 index f8f4da371..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_10.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 10). - let result: felt = fib(1, 1, 10); - - // Make sure the 10th Fibonacci number is 144. - assert result = 144; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_100.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_100.cairo deleted file mode 100644 index 6b3c2907e..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_100.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 10). - let result: felt = fib(1, 1, 100); - - // Make sure the 100th Fibonacci number is 927372692193078999176. - assert result = 927372692193078999176; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_1000.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_1000.cairo deleted file mode 100644 index d1acf9c8d..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_1000.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 1000). - let result: felt = fib(1, 1, 1000); - - // Make sure the 1000th Fibonacci number is 222450955505511890955301767713383614666194461405743219770606958667979327682. - assert result = 222450955505511890955301767713383614666194461405743219770606958667979327682; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_10000.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_10000.cairo deleted file mode 100644 index 61bb5d43a..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_10000.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 10000). - let result: felt = fib(1, 1, 10000); - - // Make sure the 10000th Fibonacci number is 2287375788429092341882876480321135809824733217263858843173749298459021701670. - assert result = 2287375788429092341882876480321135809824733217263858843173749298459021701670; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_10000_loop.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_10000_loop.cairo deleted file mode 100644 index 63ceaf213..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_10000_loop.cairo +++ /dev/null @@ -1,21 +0,0 @@ - -// Looped fibonacci is more efficient -// than calling the fibo function with recursion -// For n = 5, it's 31 steps vs 49 steps -// This is useful to compare with other vms that are not validating the call stack for fibonacci - -func main{}() { - tempvar x0 = 0; - tempvar x1 = 1; - tempvar fib_acc = x0 + x1; - tempvar n = 10000; - loop: - tempvar x0 = x1; - tempvar x1 = fib_acc; - tempvar fib_acc = x0 + x1; - tempvar n = n - 1; - jmp loop if n != 0; - - assert fib_acc = 2287375788429092341882876480321135809824733217263858843173749298459021701670; - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_5.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_5.cairo deleted file mode 100644 index 6723ba9b8..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_5.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 5). - let result: felt = fib(1, 1, 5); - - // Make sure the 5th Fibonacci number is 13. - assert result = 13; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_500.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_500.cairo deleted file mode 100644 index c2bccb34d..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_500.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 500). - let result: felt = fib(1, 1, 500); - - // Make sure the 500th Fibonacci number is 2703462216091053821850160095716009632185810905688261857143077152353261240886. - assert result = 2703462216091053821850160095716009632185810905688261857143077152353261240886; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_5_loop.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_5_loop.cairo deleted file mode 100644 index 328b2085c..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_5_loop.cairo +++ /dev/null @@ -1,21 +0,0 @@ - -// Looped fibonacci is more efficient -// than calling the fibo function with recursion -// For n = 5, it's 31 steps vs 49 steps -// This is useful to compare with other vms that are not validating the call stack for fibonacci - -func main{}() { - tempvar x0 = 0; - tempvar x1 = 1; - tempvar fib_acc = x0 + x1; - tempvar n = 5; - loop: - tempvar x0 = x1; - tempvar x1 = fib_acc; - tempvar fib_acc = x0 + x1; - tempvar n = n - 1; - jmp loop if n != 0; - - assert fib_acc = 13; - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_5_memory.bin b/provers/cairo/cairo_programs/cairo0/fibonacci_5_memory.bin deleted file mode 100644 index d27573222..000000000 Binary files a/provers/cairo/cairo_programs/cairo0/fibonacci_5_memory.bin and /dev/null differ diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_5_trace.bin b/provers/cairo/cairo_programs/cairo0/fibonacci_5_trace.bin deleted file mode 100644 index 6362f9ef7..000000000 Binary files a/provers/cairo/cairo_programs/cairo0/fibonacci_5_trace.bin and /dev/null differ diff --git a/provers/cairo/cairo_programs/cairo0/fibonacci_70000.cairo b/provers/cairo/cairo_programs/cairo0/fibonacci_70000.cairo deleted file mode 100644 index 791ab2dfb..000000000 --- a/provers/cairo/cairo_programs/cairo0/fibonacci_70000.cairo +++ /dev/null @@ -1,19 +0,0 @@ -func main() { - // Call fib(1, 1, 70000). - let result: felt = fib(1, 1, 70000); - - // Make sure the 70000th Fibonacci number is 2824861842081921227084209061704696342102277985526232307654372591609636515753. - assert result = 2824861842081921227084209061704696342102277985526232307654372591609636515753; - ret; -} - -func fib(first_element, second_element, n) -> (res: felt) { - jmp fib_body if n != 0; - tempvar result = second_element; - return (second_element,); - - fib_body: - tempvar y = first_element + second_element; - return fib(second_element, y, n - 1); -} - diff --git a/provers/cairo/cairo_programs/cairo0/lt_comparison.cairo b/provers/cairo/cairo_programs/cairo0/lt_comparison.cairo deleted file mode 100644 index bf52c5d66..000000000 --- a/provers/cairo/cairo_programs/cairo0/lt_comparison.cairo +++ /dev/null @@ -1,10 +0,0 @@ -%builtins range_check - -from starkware.cairo.common.math_cmp import is_le - -func main{range_check_ptr: felt}() { - let result = is_le(2, 6); - assert result = 1; - return (); -} - diff --git a/provers/cairo/cairo_programs/cairo0/output_program.cairo b/provers/cairo/cairo_programs/cairo0/output_program.cairo deleted file mode 100644 index 5b1a96e74..000000000 --- a/provers/cairo/cairo_programs/cairo0/output_program.cairo +++ /dev/null @@ -1,12 +0,0 @@ -%builtins output - -from starkware.cairo.common.serialize import serialize_word - -func main{output_ptr: felt*}() { - const MY_INT = 1234; - - // this will print MY_INT - serialize_word(MY_INT); - - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/rc_program.cairo b/provers/cairo/cairo_programs/cairo0/rc_program.cairo deleted file mode 100644 index a2c2614b2..000000000 --- a/provers/cairo/cairo_programs/cairo0/rc_program.cairo +++ /dev/null @@ -1,9 +0,0 @@ -%builtins range_check - -from starkware.cairo.common.math import assert_nn - -func main{range_check_ptr: felt}() { - assert_nn(5); - assert_nn(2); - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/signed_div_rem.cairo b/provers/cairo/cairo_programs/cairo0/signed_div_rem.cairo deleted file mode 100644 index 705869437..000000000 --- a/provers/cairo/cairo_programs/cairo0/signed_div_rem.cairo +++ /dev/null @@ -1,50 +0,0 @@ -%builtins output range_check -from starkware.cairo.common.math import signed_div_rem, assert_le -from starkware.cairo.common.serialize import serialize_word - -func signed_div_rem_man{range_check_ptr}(value, div, bound) -> (q: felt, r: felt) { - let r = [range_check_ptr]; - let biased_q = [range_check_ptr + 1]; // == q + bound. - let range_check_ptr = range_check_ptr + 2; - %{ - from starkware.cairo.common.math_utils import as_int, assert_integer - - assert_integer(ids.div) - assert 0 < ids.div <= PRIME // range_check_builtin.bound, \ - f'div={hex(ids.div)} is out of the valid range.' - - assert_integer(ids.bound) - assert ids.bound <= range_check_builtin.bound // 2, \ - f'bound={hex(ids.bound)} is out of the valid range.' - - int_value = as_int(ids.value, PRIME) - q, ids.r = divmod(int_value, ids.div) - - assert -ids.bound <= q < ids.bound, \ - f'{int_value} / {ids.div} = {q} is out of the range [{-ids.bound}, {ids.bound}).' - - ids.biased_q = q + ids.bound - %} - let q = biased_q - bound; - assert value = q * div + r; - assert_le(r, div - 1); - assert_le(biased_q, 2 * bound - 1); - return (q, r); -} - -func main{output_ptr: felt*, range_check_ptr: felt}() { - let (q_negative_expected, r_negative_expected) = signed_div_rem(-10, 3, 29); - let (q_negative, r_negative) = signed_div_rem_man(-10, 3, 29); - assert q_negative_expected = q_negative; - assert r_negative_expected = r_negative; - serialize_word(q_negative_expected); - serialize_word(q_negative); - serialize_word(r_negative_expected); - serialize_word(r_negative); - - let (q_expected, r_expected) = signed_div_rem(10, 3, 29); - let (q, r) = signed_div_rem_man(10, 3, 29); - assert q_expected = q; - assert r_expected = r; - return (); -} diff --git a/provers/cairo/cairo_programs/cairo0/simple_program.cairo b/provers/cairo/cairo_programs/cairo0/simple_program.cairo deleted file mode 100644 index f42affecb..000000000 --- a/provers/cairo/cairo_programs/cairo0/simple_program.cairo +++ /dev/null @@ -1,7 +0,0 @@ -func main() { - let x = 1; - let y = 2; - assert x + y = 3; - return (); -} - diff --git a/provers/cairo/ffi/Cargo.toml b/provers/cairo/ffi/Cargo.toml deleted file mode 100644 index f7437cf02..000000000 --- a/provers/cairo/ffi/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "cairo-platinum-ffi" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -# libc = "0.2" -stark-platinum-prover = { path = "../../stark" } -cairo-platinum-prover = { path = "../" } -bincode = { version = "2.0.0-rc.2", tag = "v2.0.0-rc.2", git = "https://github.com/bincode-org/bincode.git", features = ['serde'] } - -[lib] -crate-type = ["cdylib", "staticlib", "lib"] diff --git a/provers/cairo/ffi/fibo_5.proof b/provers/cairo/ffi/fibo_5.proof deleted file mode 100644 index fc112dec4..000000000 Binary files a/provers/cairo/ffi/fibo_5.proof and /dev/null differ diff --git a/provers/cairo/ffi/src/lib.rs b/provers/cairo/ffi/src/lib.rs deleted file mode 100644 index b5ea7e0a5..000000000 --- a/provers/cairo/ffi/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -use cairo_platinum_prover::air::CairoAIR; -use stark_platinum_prover::proof::options::ProofOptions; -use stark_platinum_prover::proof::options::SecurityLevel; -use stark_platinum_prover::transcript::StoneProverTranscript; -use stark_platinum_prover::verifier::{IsStarkVerifier, Verifier}; - -fn verify_cairo_proof_ffi(proof_bytes: &[u8], proof_options: &ProofOptions) -> bool { - let bytes = proof_bytes; - - // This logic is the same as main verify, with only error handling changing. In ffi, we simply return a false if the proof is invalid, instead of rising an error. - - // Proof len was stored as an u32, 4u8 needs to be read - let proof_len = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize; - - let bytes = &bytes[4..]; - if bytes.len() < proof_len { - return false; - } - - let Ok((proof, _)) = - bincode::serde::decode_from_slice(&bytes[0..proof_len], bincode::config::standard()) - else { - return false; - }; - let bytes = &bytes[proof_len..]; - - let Ok((pub_inputs, _)) = bincode::serde::decode_from_slice(bytes, bincode::config::standard()) - else { - return false; - }; - - Verifier::::verify( - &proof, - &pub_inputs, - proof_options, - StoneProverTranscript::new(&[]), - ) -} - -// Fibo 70k is 260 kb -// 2 MiB is more than enough -const MAX_PROOF_SIZE: usize = 1024 * 1024; - -/// WASM Function for verifying a proof with default 100 bits of security -#[no_mangle] -pub extern "C" fn verify_cairo_proof_ffi_100_bits( - proof_bytes: &[u8; MAX_PROOF_SIZE], - real_len: usize, -) -> bool { - let (real_proof_bytes, _) = proof_bytes.split_at(real_len); - - println!("Len: {:?} ", real_proof_bytes.len()); - let proof_options = ProofOptions::new_secure(SecurityLevel::Conjecturable100Bits, 3); - verify_cairo_proof_ffi(real_proof_bytes, &proof_options) -} - -#[cfg(test)] -mod tests { - use super::*; - - const PROOF: &[u8; 265809] = include_bytes!("../fibo_5.proof"); - - #[test] - fn fibo_5_proof_verifies() { - let mut proof_buffer = [0u8; super::MAX_PROOF_SIZE]; - let proof_size = PROOF.len(); - proof_buffer[..proof_size].clone_from_slice(PROOF); - let result = verify_cairo_proof_ffi_100_bits(&proof_buffer, proof_size); - assert!(result) - } -} diff --git a/provers/cairo/proof.proof b/provers/cairo/proof.proof deleted file mode 100644 index 82d522cb2..000000000 Binary files a/provers/cairo/proof.proof and /dev/null differ diff --git a/provers/cairo/requirements.txt b/provers/cairo/requirements.txt deleted file mode 100644 index 6e0951b92..000000000 --- a/provers/cairo/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -ecdsa==0.18.0 -bitarray==2.7.3 -fastecdsa==2.2.3 -sympy==1.11.1 -typeguard==2.13.3 -cairo-lang==0.11.0 diff --git a/provers/cairo/src/air.rs b/provers/cairo/src/air.rs deleted file mode 100644 index 2d15f5672..000000000 --- a/provers/cairo/src/air.rs +++ /dev/null @@ -1,1109 +0,0 @@ -use super::{cairo_mem::CairoMemory, register_states::RegisterStates}; -use crate::transition_constraints::*; -use cairo_vm::{air_public_input::MemorySegmentAddresses, without_std::collections::HashMap}; -#[cfg(debug_assertions)] -use itertools::Itertools; -use lambdaworks_crypto::fiat_shamir::is_transcript::IsTranscript; -use lambdaworks_math::{ - errors::DeserializationError, - field::{ - element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, - }, - traits::{AsBytes, ByteConversion, Deserializable}, -}; -use stark_platinum_prover::{ - constraints::boundary::{BoundaryConstraint, BoundaryConstraints}, - context::AirContext, - frame::Frame, - proof::{options::ProofOptions, stark::StarkProof}, - prover::{IsStarkProver, Prover, ProvingError}, - trace::TraceTable, - traits::AIR, - transcript::StoneProverTranscript, - verifier::{IsStarkVerifier, Verifier}, - Felt252, -}; -use stark_platinum_prover::{constraints::transition::TransitionConstraint, table::Table}; - -// TODO: These should probably be in the TraceTable module. -pub const FRAME_RES: usize = 16; -pub const FRAME_AP: usize = 17; -pub const FRAME_FP: usize = 18; -pub const FRAME_PC: usize = 19; -pub const FRAME_DST_ADDR: usize = 20; -pub const FRAME_OP0_ADDR: usize = 21; -pub const FRAME_OP1_ADDR: usize = 22; -pub const FRAME_INST: usize = 23; -pub const FRAME_DST: usize = 24; -pub const FRAME_OP0: usize = 25; -pub const FRAME_OP1: usize = 26; -pub const OFF_DST: usize = 27; -pub const OFF_OP0: usize = 28; -pub const OFF_OP1: usize = 29; -pub const FRAME_T0: usize = 30; -pub const FRAME_T1: usize = 31; -pub const FRAME_MUL: usize = 32; -pub const EXTRA_ADDR: usize = 33; -pub const EXTRA_VAL: usize = 34; -pub const RC_HOLES: usize = 35; - -// Auxiliary range check columns -pub const RANGE_CHECK_COL_1: usize = 0; -pub const RANGE_CHECK_COL_2: usize = 1; -pub const RANGE_CHECK_COL_3: usize = 2; -pub const RANGE_CHECK_COL_4: usize = 3; - -// Auxiliary memory columns -pub const MEMORY_ADDR_SORTED_0: usize = 4; -pub const MEMORY_ADDR_SORTED_1: usize = 5; -pub const MEMORY_ADDR_SORTED_2: usize = 6; -pub const MEMORY_ADDR_SORTED_3: usize = 7; -pub const MEMORY_ADDR_SORTED_4: usize = 8; - -pub const MEMORY_VALUES_SORTED_0: usize = 9; -pub const MEMORY_VALUES_SORTED_1: usize = 10; -pub const MEMORY_VALUES_SORTED_2: usize = 11; -pub const MEMORY_VALUES_SORTED_3: usize = 12; -pub const MEMORY_VALUES_SORTED_4: usize = 13; - -pub const PERMUTATION_ARGUMENT_COL_0: usize = 14; -pub const PERMUTATION_ARGUMENT_COL_1: usize = 15; -pub const PERMUTATION_ARGUMENT_COL_2: usize = 16; -pub const PERMUTATION_ARGUMENT_COL_3: usize = 17; -pub const PERMUTATION_ARGUMENT_COL_4: usize = 18; - -pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_1: usize = 19; -pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_2: usize = 20; -pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_3: usize = 21; -pub const PERMUTATION_ARGUMENT_RANGE_CHECK_COL_4: usize = 22; - -// Trace layout -pub const MEM_P_TRACE_OFFSET: usize = 17; -pub const MEM_A_TRACE_OFFSET: usize = 19; - -#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] -pub enum SegmentName { - RangeCheck, - Output, - Program, - Execution, - Ecdsa, - Pedersen, -} - -impl From<&str> for SegmentName { - fn from(value: &str) -> Self { - match value { - "range_check" => SegmentName::RangeCheck, - "output" => SegmentName::Output, - "program" => SegmentName::Program, - "execution" => SegmentName::Execution, - "ecdsa" => SegmentName::Ecdsa, - "pedersen" => SegmentName::Pedersen, - n => panic!("Invalid segment name {n}"), - } - } -} - -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct Segment { - pub begin_addr: usize, - pub stop_ptr: usize, -} - -impl Segment { - pub fn new(begin_addr: u64, stop_ptr: u64) -> Self { - let begin_addr: usize = begin_addr.try_into().unwrap(); - let stop_ptr: usize = stop_ptr.try_into().unwrap(); - - stop_ptr.checked_sub(begin_addr).unwrap(); - - Self { - begin_addr, - stop_ptr, - } - } - - pub fn segment_size(&self) -> usize { - self.stop_ptr - self.begin_addr - 1 - } -} - -impl From<&MemorySegmentAddresses> for Segment { - fn from(value: &MemorySegmentAddresses) -> Self { - Self { - begin_addr: value.begin_addr, - stop_ptr: value.stop_ptr, - } - } -} - -pub type MemorySegmentMap = HashMap; - -#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] -pub struct PublicInputs { - pub pc_init: Felt252, - pub ap_init: Felt252, - pub fp_init: Felt252, - pub pc_final: Felt252, - pub ap_final: Felt252, - // These are Option because they're not known until - // the trace is obtained. They represent the minimum - // and maximum offsets used during program execution. - // TODO: A possible refactor is moving them to the proof. - // minimum range check value (0 < range_check_min < range_check_max < 2^16) - pub range_check_min: Option, - // maximum range check value - pub range_check_max: Option, - // Range-check builtin address range - pub memory_segments: MemorySegmentMap, - pub public_memory: HashMap, - pub num_steps: usize, // number of execution steps -} - -impl PublicInputs { - /// Creates a Public Input from register states and memory - /// - In the future we should use the output of the Cairo Runner. This is not currently supported in Cairo RS - /// - RangeChecks are not filled, and the prover mutates them inside the prove function. This works but also should be loaded from the Cairo RS output - pub fn from_regs_and_mem( - register_states: &RegisterStates, - memory: &CairoMemory, - codelen: usize, - ) -> Self { - let public_memory = (1..=codelen as u64) - .map(|i| (Felt252::from(i), *memory.get(&i).unwrap())) - .collect::>(); - - let last_step = ®ister_states.rows[register_states.steps() - 1]; - - PublicInputs { - pc_init: Felt252::from(register_states.rows[0].pc), - ap_init: Felt252::from(register_states.rows[0].ap), - fp_init: Felt252::from(register_states.rows[0].fp), - pc_final: FieldElement::from(last_step.pc), - ap_final: FieldElement::from(last_step.ap), - range_check_min: None, - range_check_max: None, - memory_segments: MemorySegmentMap::new(), - public_memory, - num_steps: register_states.steps(), - } - } -} - -impl AsBytes for PublicInputs { - fn as_bytes(&self) -> Vec { - let mut bytes = vec![]; - let pc_init_bytes = self.pc_init.to_bytes_be(); - let felt_length = pc_init_bytes.len(); - bytes.extend(felt_length.to_be_bytes()); - bytes.extend(pc_init_bytes); - bytes.extend(self.ap_init.to_bytes_be()); - bytes.extend(self.fp_init.to_bytes_be()); - bytes.extend(self.pc_final.to_bytes_be()); - bytes.extend(self.ap_final.to_bytes_be()); - - if let Some(range_check_min) = self.range_check_min { - bytes.extend(1u8.to_be_bytes()); - bytes.extend(range_check_min.to_be_bytes()); - } else { - bytes.extend(0u8.to_be_bytes()); - } - - if let Some(range_check_max) = self.range_check_max { - bytes.extend(1u8.to_be_bytes()); - bytes.extend(range_check_max.to_be_bytes()); - } else { - bytes.extend(0u8.to_be_bytes()); - } - - let mut memory_segment_bytes = vec![]; - for (segment, range) in self.memory_segments.iter() { - let segment_type = match segment { - SegmentName::RangeCheck => 0u8, - SegmentName::Output => 1u8, - SegmentName::Program => 2u8, - SegmentName::Execution => 3u8, - SegmentName::Ecdsa => 4u8, - SegmentName::Pedersen => 5u8, - }; - memory_segment_bytes.extend(segment_type.to_be_bytes()); - memory_segment_bytes.extend(range.begin_addr.to_be_bytes()); - memory_segment_bytes.extend(range.stop_ptr.to_be_bytes()); - } - let memory_segment_length = self.memory_segments.len(); - bytes.extend(memory_segment_length.to_be_bytes()); - bytes.extend(memory_segment_bytes); - - let mut public_memory_bytes = vec![]; - for (address, value) in self.public_memory.iter() { - public_memory_bytes.extend(address.to_bytes_be()); - public_memory_bytes.extend(value.to_bytes_be()); - } - let public_memory_length = self.public_memory.len(); - bytes.extend(public_memory_length.to_be_bytes()); - bytes.extend(public_memory_bytes); - - bytes.extend(self.num_steps.to_be_bytes()); - - bytes - } -} - -impl Deserializable for PublicInputs { - fn deserialize(bytes: &[u8]) -> Result - where - Self: Sized, - { - let mut bytes = bytes; - let felt_len = usize::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[8..]; - let pc_init = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - let ap_init = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - let fp_init = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - let pc_final = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - let ap_final = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - - if bytes.is_empty() { - return Err(DeserializationError::InvalidAmountOfBytes); - } - let range_check_min = match bytes[0] { - 0 => { - bytes = &bytes[1..]; - None - } - 1 => { - bytes = &bytes[1..]; - let range_check_min = u16::from_be_bytes( - bytes[..2] - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[2..]; - Some(range_check_min) - } - _ => return Err(DeserializationError::FieldFromBytesError), - }; - - if bytes.is_empty() { - return Err(DeserializationError::InvalidAmountOfBytes); - } - let range_check_max = match bytes[0] { - 0 => { - bytes = &bytes[1..]; - None - } - 1 => { - bytes = &bytes[1..]; - let range_check_max = u16::from_be_bytes( - bytes[..2] - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[2..]; - Some(range_check_max) - } - _ => return Err(DeserializationError::FieldFromBytesError), - }; - - let mut memory_segments = MemorySegmentMap::new(); - let memory_segment_length = usize::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[8..]; - for _ in 0..memory_segment_length { - if bytes.is_empty() { - return Err(DeserializationError::InvalidAmountOfBytes); - } - let segment_type = match bytes[0] { - 0u8 => SegmentName::RangeCheck, - 1u8 => SegmentName::Output, - 2u8 => SegmentName::Program, - 3u8 => SegmentName::Execution, - 4u8 => SegmentName::Ecdsa, - 5u8 => SegmentName::Pedersen, - _ => return Err(DeserializationError::FieldFromBytesError), - }; - bytes = &bytes[1..]; - let start = u64::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[8..]; - let end = u64::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[8..]; - memory_segments.insert(segment_type, Segment::new(start, end)); - } - - let mut public_memory = HashMap::new(); - let public_memory_length = usize::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - bytes = &bytes[8..]; - for _ in 0..public_memory_length { - let address = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - let value = Felt252::from_bytes_be( - bytes - .get(..felt_len) - .ok_or(DeserializationError::InvalidAmountOfBytes)?, - )?; - bytes = &bytes[felt_len..]; - public_memory.insert(address, value); - } - - let num_steps = usize::from_be_bytes( - bytes - .get(0..8) - .ok_or(DeserializationError::InvalidAmountOfBytes)? - .try_into() - .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, - ); - - Ok(Self { - pc_init, - ap_init, - fp_init, - pc_final, - ap_final, - range_check_min, - range_check_max, - memory_segments, - public_memory, - num_steps, - }) - } -} - -pub struct CairoAIR { - pub context: AirContext, - pub trace_length: usize, - pub pub_inputs: PublicInputs, - pub transition_constraints: - Vec>>, -} - -/// Receives two slices corresponding to the accessed addresses and values, filled with -/// the memory holes and with the (0, 0) public memory dummy accesses. -/// Each (address, value) public memory pair is written in a (0, 0) dummy access until -/// there is no one left. -/// -/// NOTE: At the end of this process there might be some additional (0, 0) dummy accesses -/// that were not overwritten. This is not a problem as long as all the public memory pairs -/// have been written. -fn add_pub_memory_in_public_input_section( - addresses: &[Felt252], - values: &[Felt252], - public_input: &PublicInputs, -) -> (Vec, Vec) { - let mut a_aux = addresses.to_owned(); - let mut v_aux = values.to_owned(); - - let mut pub_addrs = public_input.public_memory.iter(); - - // Iterate over addresses - for (i, a) in a_aux.iter_mut().enumerate() { - // When address `0` is found, it means it corresponds to a dummy access. - if a == &Felt252::zero() { - // While there are public memory addresses left, overwrite the dummy - // (addr, value) accesses with the real public memory pairs. - if let Some((pub_addr, pub_value)) = pub_addrs.next() { - *a = *pub_addr; - v_aux[i] = *pub_value; - } else { - // When there are no public memory pairs left to write, break the - // loop and return the (addr, value) pairs with dummy accesses - // overwritten. - break; - } - } - } - - (a_aux, v_aux) -} - -fn sort_columns_by_memory_address( - adresses: Vec, - values: Vec, -) -> (Vec, Vec) { - let mut tuples: Vec<_> = adresses.into_iter().zip(values).collect(); - tuples.sort_by(|(x, _), (y, _)| x.representative().cmp(&y.representative())); - tuples.into_iter().unzip() -} - -fn generate_memory_permutation_argument_column( - addresses_original: Vec, - values_original: Vec, - addresses_sorted: &[Felt252], - values_sorted: &[Felt252], - rap_challenges: &[Felt252], -) -> Vec { - let z = &rap_challenges[1]; - let alpha = &rap_challenges[0]; - - let mut denom: Vec<_> = addresses_sorted - .iter() - .zip(values_sorted) - .map(|(ap, vp)| z - (ap + alpha * vp)) - .collect(); - FieldElement::inplace_batch_inverse(&mut denom).unwrap(); - // Returns the cumulative products of the numerators and denominators - addresses_original - .iter() - .zip(&values_original) - .zip(&denom) - .scan(Felt252::one(), |product, ((a_i, v_i), den_i)| { - let ret = *product; - *product = ret * ((z - (a_i + alpha * v_i)) * den_i); - Some(*product) - }) - .collect::>() -} - -fn generate_range_check_permutation_argument_column( - offset_column_original: &[Felt252], - offset_column_sorted: &[Felt252], - rap_challenges: &[Felt252], -) -> Vec { - let z = rap_challenges[2]; - - let mut denom: Vec<_> = offset_column_sorted.iter().map(|x| z - x).collect(); - FieldElement::inplace_batch_inverse(&mut denom).unwrap(); - - offset_column_original - .iter() - .zip(&denom) - .scan(Felt252::one(), |product, (num_i, den_i)| { - let ret = *product; - *product = ret * (z - num_i) * den_i; - Some(*product) - }) - .collect::>() -} - -impl AIR for CairoAIR { - type Field = Stark252PrimeField; - type FieldExtension = Stark252PrimeField; - type PublicInputs = PublicInputs; - - const STEP_SIZE: usize = 1; - - /// Creates a new CairoAIR from proof_options - /// - /// # Arguments - /// - /// * `trace_length` - Length of the Cairo execution trace. Must be a power fo two. - /// * `pub_inputs` - Public inputs sent by the Cairo runner. - /// * `proof_options` - STARK proving configuration options. - fn new( - trace_length: usize, - pub_inputs: &Self::PublicInputs, - proof_options: &ProofOptions, - ) -> Self { - debug_assert!(trace_length.is_power_of_two()); - let trace_columns = 59; - - let transition_constraints: Vec< - Box>, - > = vec![ - Box::new(BitPrefixFlag0::new()), - Box::new(BitPrefixFlag1::new()), - Box::new(BitPrefixFlag2::new()), - Box::new(BitPrefixFlag3::new()), - Box::new(BitPrefixFlag4::new()), - Box::new(BitPrefixFlag5::new()), - Box::new(BitPrefixFlag6::new()), - Box::new(BitPrefixFlag7::new()), - Box::new(BitPrefixFlag8::new()), - Box::new(BitPrefixFlag9::new()), - Box::new(BitPrefixFlag10::new()), - Box::new(BitPrefixFlag11::new()), - Box::new(BitPrefixFlag12::new()), - Box::new(BitPrefixFlag13::new()), - Box::new(BitPrefixFlag14::new()), - Box::new(ZeroFlagConstraint::new()), - Box::new(InstructionUnpacking::new()), - Box::new(CpuOperandsMemDstAddr::new()), - Box::new(CpuOperandsMem0Addr::new()), - Box::new(CpuOperandsMem1Addr::new()), - Box::new(CpuUpdateRegistersApUpdate::new()), - Box::new(CpuUpdateRegistersFpUpdate::new()), - Box::new(CpuUpdateRegistersPcCondPositive::new()), - Box::new(CpuUpdateRegistersPcCondNegative::new()), - Box::new(CpuUpdateRegistersUpdatePcTmp0::new()), - Box::new(CpuUpdateRegistersUpdatePcTmp1::new()), - Box::new(CpuOperandsOpsMul::new()), - Box::new(CpuOperandsRes::new()), - Box::new(CpuOpcodesCallPushFp::new()), - Box::new(CpuOpcodesCallPushPc::new()), - Box::new(CpuOpcodesAssertEq::new()), - Box::new(MemoryDiffIsBit0::new()), - Box::new(MemoryDiffIsBit1::new()), - Box::new(MemoryDiffIsBit2::new()), - Box::new(MemoryDiffIsBit3::new()), - Box::new(MemoryDiffIsBit4::new()), - Box::new(MemoryIsFunc0::new()), - Box::new(MemoryIsFunc1::new()), - Box::new(MemoryIsFunc2::new()), - Box::new(MemoryIsFunc3::new()), - Box::new(MemoryIsFunc4::new()), - Box::new(MemoryMultiColumnPermStep0_0::new()), - Box::new(MemoryMultiColumnPermStep0_1::new()), - Box::new(MemoryMultiColumnPermStep0_2::new()), - Box::new(MemoryMultiColumnPermStep0_3::new()), - Box::new(MemoryMultiColumnPermStep0_4::new()), - Box::new(Rc16DiffIsBit0::new()), - Box::new(Rc16DiffIsBit1::new()), - Box::new(Rc16DiffIsBit2::new()), - Box::new(Rc16DiffIsBit3::new()), - Box::new(Rc16PermStep0_0::new()), - Box::new(Rc16PermStep0_1::new()), - Box::new(Rc16PermStep0_2::new()), - Box::new(Rc16PermStep0_3::new()), - Box::new(FlagOp1BaseOp0BitConstraint::new()), - Box::new(FlagResOp1BitConstraint::new()), - Box::new(FlagPcUpdateRegularBit::new()), - Box::new(FlagFpUpdateRegularBit::new()), - Box::new(CpuOpcodesCallOff0::new()), - Box::new(CpuOpcodesCallOff1::new()), - Box::new(CpuOpcodesCallFlags::new()), - Box::new(CpuOpcodesRetOff0::new()), - Box::new(CpuOpcodesRetOff2::new()), - Box::new(CpuOpcodesRetFlags::new()), - ]; - - #[cfg(debug_assertions)] - { - use std::collections::HashSet; - let constraints_set: HashSet<_> = transition_constraints - .iter() - .map(|c| c.constraint_idx()) - .collect(); - debug_assert_eq!( - constraints_set.len(), - transition_constraints.len(), - "There are repeated constraint indexes" - ); - (0..transition_constraints.len()) - .for_each(|idx| debug_assert!(constraints_set.iter().contains(&idx))); - - assert_eq!(transition_constraints.len(), 64); - } - - assert_eq!(transition_constraints.len(), 64); - - let transition_exemptions = transition_constraints - .iter() - .map(|c| c.end_exemptions()) - .collect(); - - let context = AirContext { - proof_options: proof_options.clone(), - trace_columns, - transition_exemptions, - transition_offsets: vec![0, 1], - num_transition_constraints: transition_constraints.len(), - }; - - // The number of the transition constraints - // and transition exemptions should be the same always. - debug_assert_eq!( - context.transition_exemptions.len(), - context.num_transition_constraints - ); - - Self { - context, - pub_inputs: pub_inputs.clone(), - trace_length, - transition_constraints, - } - } - - fn build_auxiliary_trace( - &self, - main_trace: &TraceTable, - rap_challenges: &[Felt252], - ) -> TraceTable { - let addresses_original = main_trace.merge_columns(&[ - FRAME_PC, - FRAME_DST_ADDR, - FRAME_OP0_ADDR, - FRAME_OP1_ADDR, - EXTRA_ADDR, - ]); - - let values_original = - main_trace.merge_columns(&[FRAME_INST, FRAME_DST, FRAME_OP0, FRAME_OP1, EXTRA_VAL]); - - let (addresses, values) = add_pub_memory_in_public_input_section( - &addresses_original, - &values_original, - &self.pub_inputs, - ); - - let (addresses, values) = sort_columns_by_memory_address(addresses, values); - - let permutation_col = generate_memory_permutation_argument_column( - addresses_original, - values_original, - &addresses, - &values, - rap_challenges, - ); - - // Range Check - let offsets_original = main_trace.merge_columns(&[OFF_DST, OFF_OP0, OFF_OP1, RC_HOLES]); - - let mut offsets_sorted: Vec = offsets_original - .iter() - .map(|x| x.representative().into()) - .collect(); - offsets_sorted.sort(); - let offsets_sorted: Vec<_> = offsets_sorted - .iter() - .map(|x| FieldElement::from(*x as u64)) - .collect(); - - let range_check_permutation_col = generate_range_check_permutation_argument_column( - &offsets_original, - &offsets_sorted, - rap_challenges, - ); - - // Convert from long-format to wide-format again - let mut aux_data = Vec::new(); - for i in 0..main_trace.n_rows() { - aux_data.push(offsets_sorted[4 * i]); - aux_data.push(offsets_sorted[4 * i + 1]); - aux_data.push(offsets_sorted[4 * i + 2]); - aux_data.push(offsets_sorted[4 * i + 3]); - aux_data.push(addresses[5 * i]); - aux_data.push(addresses[5 * i + 1]); - aux_data.push(addresses[5 * i + 2]); - aux_data.push(addresses[5 * i + 3]); - aux_data.push(addresses[5 * i + 4]); - aux_data.push(values[5 * i]); - aux_data.push(values[5 * i + 1]); - aux_data.push(values[5 * i + 2]); - aux_data.push(values[5 * i + 3]); - aux_data.push(values[5 * i + 4]); - aux_data.push(permutation_col[5 * i]); - aux_data.push(permutation_col[5 * i + 1]); - aux_data.push(permutation_col[5 * i + 2]); - aux_data.push(permutation_col[5 * i + 3]); - aux_data.push(permutation_col[5 * i + 4]); - aux_data.push(range_check_permutation_col[4 * i]); - aux_data.push(range_check_permutation_col[4 * i + 1]); - aux_data.push(range_check_permutation_col[4 * i + 2]); - aux_data.push(range_check_permutation_col[4 * i + 3]); - } - - let aux_table = Table::new(aux_data, self.num_auxiliary_rap_columns()); - - let (num_main_columns, num_aux_columns) = self.trace_layout(); - TraceTable { - table: aux_table, - num_main_columns, - num_aux_columns, - step_size: Self::STEP_SIZE, - } - } - - fn build_rap_challenges( - &self, - transcript: &mut impl IsTranscript, - ) -> Vec { - let alpha_memory = transcript.sample_field_element(); - let z_memory = transcript.sample_field_element(); - let z_rc = transcript.sample_field_element(); - - vec![alpha_memory, z_memory, z_rc] - } - - fn trace_layout(&self) -> (usize, usize) { - (36, 23) - } - - /// From the Cairo whitepaper, section 9.10. - /// These are part of the register constraints. - /// - /// Boundary constraints: - /// * ap_0 = fp_0 = ap_i - /// * ap_t = ap_f - /// * pc_0 = pc_i - /// * pc_t = pc_f - fn boundary_constraints(&self, rap_challenges: &[Felt252]) -> BoundaryConstraints { - let initial_pc = - BoundaryConstraint::new_main(MEM_A_TRACE_OFFSET, 0, self.pub_inputs.pc_init); - let initial_ap = - BoundaryConstraint::new_main(MEM_P_TRACE_OFFSET, 0, self.pub_inputs.ap_init); - - let final_pc = BoundaryConstraint::new_main( - MEM_A_TRACE_OFFSET, - self.pub_inputs.num_steps - 1, - self.pub_inputs.pc_final, - ); - let final_ap = BoundaryConstraint::new_main( - MEM_P_TRACE_OFFSET, - self.pub_inputs.num_steps - 1, - self.pub_inputs.ap_final, - ); - - // Auxiliary constraint: permutation argument final value - let final_index = self.trace_length - 1; - - let z_memory = rap_challenges[1]; - let alpha_memory = rap_challenges[0]; - - let cumulative_product = self - .pub_inputs - .public_memory - .iter() - .fold(FieldElement::one(), |product, (address, value)| { - product * (z_memory - (address + alpha_memory * value)) - }) - .inv() - .unwrap(); - - let permutation_final = - z_memory.pow(self.pub_inputs.public_memory.len()) * cumulative_product; - - let permutation_final_constraint = - BoundaryConstraint::new_aux(PERMUTATION_ARGUMENT_COL_4, final_index, permutation_final); - - let one: FieldElement = FieldElement::one(); - let range_check_final_constraint = - BoundaryConstraint::new_aux(PERMUTATION_ARGUMENT_RANGE_CHECK_COL_4, final_index, one); - - let range_check_min = BoundaryConstraint::new_aux( - RANGE_CHECK_COL_1, - 0, - FieldElement::from(self.pub_inputs.range_check_min.unwrap() as u64), - ); - - let range_check_max = BoundaryConstraint::new_aux( - RANGE_CHECK_COL_4, - final_index, - FieldElement::from(self.pub_inputs.range_check_max.unwrap() as u64), - ); - - let constraints = vec![ - initial_pc, - initial_ap, - final_pc, - final_ap, - permutation_final_constraint, - range_check_final_constraint, - range_check_min, - range_check_max, - ]; - - BoundaryConstraints::from_constraints(constraints) - } - - fn transition_constraints( - &self, - ) -> &Vec>> { - &self.transition_constraints - } - - fn context(&self) -> &AirContext { - &self.context - } - - fn composition_poly_degree_bound(&self) -> usize { - 2 * self.trace_length - } - - fn trace_length(&self) -> usize { - self.trace_length - } - - fn pub_inputs(&self) -> &Self::PublicInputs { - &self.pub_inputs - } - - fn compute_transition_verifier( - &self, - frame: &Frame, - periodic_values: &[FieldElement], - rap_challenges: &[FieldElement], - ) -> Vec> { - self.compute_transition_prover(frame, periodic_values, rap_challenges) - } -} - -/// Wrapper function for generating Cairo proofs without the need to specify -/// concrete types. -/// The field is set to Stark252PrimeField and the AIR to CairoAIR. -pub fn generate_cairo_proof( - trace: &TraceTable, - pub_input: &PublicInputs, - proof_options: &ProofOptions, -) -> Result, ProvingError> { - Prover::::prove( - trace, - pub_input, - proof_options, - StoneProverTranscript::new(&[]), - ) -} - -/// Wrapper function for verifying Cairo proofs without the need to specify -/// concrete types. -/// The field is set to Stark252PrimeField and the AIR to CairoAIR. -pub fn verify_cairo_proof( - proof: &StarkProof, - pub_input: &PublicInputs, - proof_options: &ProofOptions, -) -> bool { - Verifier::::verify( - proof, - pub_input, - proof_options, - StoneProverTranscript::new(&[]), - ) -} - -#[cfg(test)] -#[cfg(debug_assertions)] -mod test { - use super::*; - use lambdaworks_math::field::element::FieldElement; - - #[test] - fn test_build_auxiliary_trace_sort_columns_by_memory_address() { - let a = vec![ - FieldElement::from(2), - FieldElement::one(), - FieldElement::from(3), - FieldElement::from(2), - ]; - let v = vec![ - FieldElement::from(6), - FieldElement::from(4), - FieldElement::from(5), - FieldElement::from(6), - ]; - let (ap, vp) = sort_columns_by_memory_address(a, v); - assert_eq!( - ap, - vec![ - FieldElement::one(), - FieldElement::from(2), - FieldElement::from(2), - FieldElement::from(3) - ] - ); - assert_eq!( - vp, - vec![ - FieldElement::from(4), - FieldElement::from(6), - FieldElement::from(6), - FieldElement::from(5), - ] - ); - } - - #[test] - fn test_build_auxiliary_trace_generate_permutation_argument_column() { - let a = vec![ - FieldElement::from(3), - FieldElement::one(), - FieldElement::from(2), - ]; - let v = vec![ - FieldElement::from(5), - FieldElement::one(), - FieldElement::from(2), - ]; - let ap = vec![ - FieldElement::one(), - FieldElement::from(2), - FieldElement::from(3), - ]; - let vp = vec![ - FieldElement::one(), - FieldElement::from(2), - FieldElement::from(5), - ]; - let rap_challenges = vec![ - FieldElement::from(15), - FieldElement::from(10), - FieldElement::zero(), - ]; - - let p = generate_memory_permutation_argument_column(a, v, &ap, &vp, &rap_challenges); - assert_eq!( - p, - vec![ - FieldElement::from_hex( - "2aaaaaaaaaaaab0555555555555555555555555555555555555555555555561" - ) - .unwrap(), - FieldElement::from_hex( - "1745d1745d174602e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2e8ba2ec" - ) - .unwrap(), - FieldElement::one(), - ] - ); - } -} - -#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))] -#[cfg(test)] -mod prop_test { - use lambdaworks_math::{ - field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, - traits::{AsBytes, Deserializable}, - }; - use proptest::{prelude::*, prop_compose, proptest}; - use stark_platinum_prover::proof::{options::ProofOptions, stark::StarkProof}; - - use crate::{ - air::{generate_cairo_proof, verify_cairo_proof}, - cairo_layout::CairoLayout, - runner::run::generate_prover_args, - tests::utils::cairo0_program_path, - Felt252, - }; - - use super::{MemorySegmentMap, PublicInputs, Segment, SegmentName}; - - prop_compose! { - fn some_felt()(base in any::(), exponent in any::()) -> Felt252 { - Felt252::from(base).pow(exponent) - } - } - - prop_compose! { - fn some_public_inputs()( - pc_init in some_felt(), - ap_init in some_felt(), - fp_init in some_felt(), - pc_final in some_felt(), - ap_final in some_felt(), - public_memory in proptest::collection::hash_map(any::(), any::(), (8_usize, 16_usize)), - range_check_max in proptest::option::of(any::()), - range_check_min in proptest::option::of(any::()), - num_steps in any::(), - ) -> PublicInputs { - let public_memory = public_memory.iter().map(|(k, v)| (Felt252::from(*k), Felt252::from(*v))).collect(); - let memory_segments = MemorySegmentMap::from([(SegmentName::Output, Segment::new(10u64, 16u64)), (SegmentName::RangeCheck, Segment::new(20u64, 71u64))]); - PublicInputs { - pc_init, - ap_init, - fp_init, - pc_final, - ap_final, - public_memory, - range_check_max, - range_check_min, - num_steps, - memory_segments, - } - } - } - - proptest! { - #![proptest_config(ProptestConfig {cases: 5, .. ProptestConfig::default()})] - #[test] - fn test_public_inputs_serialization( - public_inputs in some_public_inputs(), - ){ - let serialized = AsBytes::as_bytes(&public_inputs); - let deserialized: PublicInputs = Deserializable::deserialize(&serialized).unwrap(); - prop_assert_eq!(public_inputs.pc_init, deserialized.pc_init); - prop_assert_eq!(public_inputs.ap_init, deserialized.ap_init); - prop_assert_eq!(public_inputs.fp_init, deserialized.fp_init); - prop_assert_eq!(public_inputs.pc_final, deserialized.pc_final); - prop_assert_eq!(public_inputs.ap_final, deserialized.ap_final); - prop_assert_eq!(public_inputs.public_memory, deserialized.public_memory); - prop_assert_eq!(public_inputs.range_check_max, deserialized.range_check_max); - prop_assert_eq!(public_inputs.range_check_min, deserialized.range_check_min); - prop_assert_eq!(public_inputs.num_steps, deserialized.num_steps); - prop_assert_eq!(public_inputs.memory_segments, deserialized.memory_segments); - } - } - - #[test] - fn deserialize_and_verify() { - let program_content = std::fs::read(cairo0_program_path("fibonacci_10.json")).unwrap(); - let (main_trace, pub_inputs) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - let proof_options = ProofOptions::default_test_options(); - - // The proof is generated and serialized. - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - let proof_bytes: Vec = serde_cbor::to_vec(&proof).unwrap(); - - // The trace and original proof are dropped to show that they are decoupled from - // the verifying process. - drop(main_trace); - drop(proof); - - // At this point, the verifier only knows about the serialized proof, the proof options - // and the public inputs. - let proof: StarkProof = - serde_cbor::from_slice(&proof_bytes).unwrap(); - - // The proof is verified successfully. - assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options)); - } -} diff --git a/provers/cairo/src/cairo_layout.rs b/provers/cairo/src/cairo_layout.rs deleted file mode 100644 index 13a7ae227..000000000 --- a/provers/cairo/src/cairo_layout.rs +++ /dev/null @@ -1,30 +0,0 @@ -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum CairoLayout { - Plain, - Small, - Dex, - Recursive, - Starknet, - StarknetWithKeccak, - RecursiveLargeOutput, - AllCairo, - AllSolidity, - Dynamic, -} - -impl CairoLayout { - pub fn as_str(&self) -> &'static str { - match self { - CairoLayout::Plain => "plain", - CairoLayout::Small => "small", - CairoLayout::Dex => "dex", - CairoLayout::Recursive => "recursive", - CairoLayout::Starknet => "starknet", - CairoLayout::StarknetWithKeccak => "starknet_with_keccak", - CairoLayout::RecursiveLargeOutput => "recursive_large_output", - CairoLayout::AllCairo => "all_cairo", - CairoLayout::AllSolidity => "all_solidity", - CairoLayout::Dynamic => "dynamic", - } - } -} diff --git a/provers/cairo/src/cairo_mem.rs b/provers/cairo/src/cairo_mem.rs deleted file mode 100644 index 3079d9ca1..000000000 --- a/provers/cairo/src/cairo_mem.rs +++ /dev/null @@ -1,130 +0,0 @@ -use super::errors::CairoImportError; -use crate::Felt252; -use lambdaworks_math::traits::ByteConversion; -use std::{collections::HashMap, fs}; - -// `Felt252` is used as the type of values stored in -// the Cairo memory. We should decide if this is -// correct or we should consider another type. -#[derive(Clone, Debug, PartialEq)] -pub struct CairoMemory { - pub data: HashMap, -} - -impl CairoMemory { - pub fn new(data: HashMap) -> Self { - Self { data } - } - - /// Given a memory address, gets the value stored in it if - /// the address exists. - pub fn get(&self, addr: &u64) -> Option<&Felt252> { - self.data.get(addr) - } - - pub fn len(&self) -> usize { - self.data.len() - } - - pub fn is_empty(&self) -> bool { - self.data.is_empty() - } - - pub fn from_bytes_le(bytes: &[u8]) -> Result { - // Each row is an 8 bytes address - // and a value of 32 bytes (which is a field) - const ROW_SIZE: usize = 8 + 32; - - if bytes.len() % ROW_SIZE != 0 { - return Err(CairoImportError::IncorrectNumberOfBytes); - } - let num_rows = bytes.len() / ROW_SIZE; - - let mut data = HashMap::with_capacity(num_rows); - - for i in 0..num_rows { - let address = - u64::from_le_bytes(bytes[i * ROW_SIZE..i * ROW_SIZE + 8].try_into().unwrap()); - let value = Felt252::from_bytes_le( - bytes[i * ROW_SIZE + 8..i * ROW_SIZE + 40] - .try_into() - .unwrap(), - ) - .unwrap(); - - data.insert(address, value); - } - - Ok(Self::new(data)) - } - - pub fn from_file(path: &str) -> Result { - let data = fs::read(path)?; - Self::from_bytes_le(&data) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn mem_indexes_are_contiguos_in_bytes_of_mul_program() { - /* - Hex from the trace of the following cairo program - - func main() { - let x = 2; - let y = 3; - assert x * y = 6; - return(); - } - - Generated with: - - cairo-compile multiply.cairo --output multiply.out - - cairo-run --layout all --trace_file trace.out --memory_file mem.out --program multiply.out - - xxd -p mem.out - */ - - let bytes = hex::decode("01000000000000000080ff7f01800648000000000000000000000000000000000000000000000000020000000000000006000000000000000000000000000000000000000000000000000000000000000300000000000000ff7fff7f01800640000000000000000000000000000000000000000000000000040000000000000006000000000000000000000000000000000000000000000000000000000000000500000000000000fe7fff7fff7f8b20000000000000000000000000000000000000000000000000060000000000000009000000000000000000000000000000000000000000000000000000000000000700000000000000090000000000000000000000000000000000000000000000000000000000000008000000000000000600000000000000000000000000000000000000000000000000000000000000").unwrap(); - - let memory = CairoMemory::from_bytes_le(&bytes).unwrap(); - - let mut sorted_addrs = memory.data.into_keys().collect::>(); - sorted_addrs.sort(); - - for (i, addr) in sorted_addrs.into_iter().enumerate() { - assert_eq!(addr, (i + 1) as u64); - } - } - - #[test] - fn test_wrong_amount_of_bytes_gives_err() { - let bytes = hex::decode("01000000000000000080ff7f01800648000000000000000000000000000000000000000000000000020000000000000006000000000000000000000000000000000000000000000000000000000000000300000000000000ff7fff7f01800640000000000000000000000000000000000000000000000000040000000000000006000000000000000000000000000000000000000000000000000000000000000500000000000000fe7fff7fff7f8b2000000000000000000000000000000000000000000000000006000000000000000900000000000000000000000000000000000000000000000000000000000000070000000000000009000000000000000000000000000000000000000000000000000000000000000800000000000000060000000000000000000000000000000000000000000000000000000000000088").unwrap(); - - match CairoMemory::from_bytes_le(&bytes) { - Err(CairoImportError::IncorrectNumberOfBytes) => (), - Err(_) => panic!(), - Ok(_) => panic!(), - } - } - - #[test] - fn mem_indexes_are_contiguos_when_loading_from_file_mul_program() { - let base_dir = env!("CARGO_MANIFEST_DIR"); - dbg!(base_dir); - let dir = base_dir.to_owned() + "/src/tests/data/mul_mem.out"; - - let memory = CairoMemory::from_file(&dir).unwrap(); - - let mut sorted_addrs = memory.data.into_keys().collect::>(); - sorted_addrs.sort(); - - for (i, addr) in sorted_addrs.into_iter().enumerate() { - assert_eq!(addr, (i + 1) as u64); - } - } -} diff --git a/provers/cairo/src/commands.rs b/provers/cairo/src/commands.rs deleted file mode 100644 index 7c81a02e1..000000000 --- a/provers/cairo/src/commands.rs +++ /dev/null @@ -1,64 +0,0 @@ -use clap::{Args, Parser, Subcommand}; - -#[derive(Parser, Debug)] -#[command(author = "Lambdaworks", version, about)] -pub struct ProverArgs { - #[clap(subcommand)] - pub entity: ProverEntity, -} - -#[derive(Subcommand, Debug)] -pub enum ProverEntity { - #[clap(about = "Compile a given cairo program")] - Compile(CompileArgs), - #[clap(about = "Run and generate a proof for a given compiled cairo program")] - RunAndProve(RunAndProveArgs), - #[clap(about = "Generate a proof from a given trace of a cairo program execution")] - Prove(ProveArgs), - #[clap(about = "Verify a proof for a given compiled cairo program")] - Verify(VerifyArgs), - #[clap(about = "Generate and verify a proof for a given compiled cairo program")] - ProveAndVerify(ProveAndVerifyArgs), - #[clap(about = "Compile and prove a given cairo program")] - CompileAndProve(CompileAndProveArgs), - #[clap(about = "Compile, prove and verify a given cairo program")] - CompileProveAndVerify(CompileAndRunAllArgs), -} - -#[derive(Args, Debug)] -pub struct CompileArgs { - pub program_path: String, -} - -#[derive(Args, Debug)] -pub struct RunAndProveArgs { - pub program_path: String, - pub proof_path: String, -} -#[derive(Args, Debug)] -pub struct ProveArgs { - pub trace_bin_path: String, - pub memory_bin_path: String, - pub proof_path: String, -} - -#[derive(Args, Debug)] -pub struct VerifyArgs { - pub proof_path: String, -} - -#[derive(Args, Debug)] -pub struct ProveAndVerifyArgs { - pub program_path: String, -} - -#[derive(Args, Debug)] -pub struct CompileAndProveArgs { - pub program_path: String, - pub proof_path: String, -} - -#[derive(Args, Debug)] -pub struct CompileAndRunAllArgs { - pub program_path: String, -} diff --git a/provers/cairo/src/decode/instruction_flags.rs b/provers/cairo/src/decode/instruction_flags.rs deleted file mode 100644 index d049e6ee9..000000000 --- a/provers/cairo/src/decode/instruction_flags.rs +++ /dev/null @@ -1,771 +0,0 @@ -use crate::{errors::InstructionDecodingError, Felt252}; - -// Constants for instructions decoding -const DST_REG_MASK: u64 = 0x0001; -const DST_REG_OFF: u64 = 0; -const OP0_REG_MASK: u64 = 0x0002; -const OP0_REG_OFF: u64 = 1; -const OP1_SRC_MASK: u64 = 0x001C; -const OP1_SRC_OFF: u64 = 2; -const RES_LOGIC_MASK: u64 = 0x0060; -const RES_LOGIC_OFF: u64 = 5; -const PC_UPDATE_MASK: u64 = 0x0380; -const PC_UPDATE_OFF: u64 = 7; -const AP_UPDATE_MASK: u64 = 0x0C00; -const AP_UPDATE_OFF: u64 = 10; -const OPCODE_MASK: u64 = 0x7000; -const OPCODE_OFF: u64 = 12; -const FLAGS_OFFSET: u64 = 48; - -// TODO: This is just an auxiliary function done to get out of the way. -// It should be deleted afterwards -pub(crate) fn aux_get_last_nim_of_field_element(value: &Felt252) -> u64 { - let mem_value_bytes = value.to_bytes_be(); - - // we are taking the last nim of the field element, - // since it is a U256 - u64::from_be_bytes([ - mem_value_bytes[24], - mem_value_bytes[25], - mem_value_bytes[26], - mem_value_bytes[27], - mem_value_bytes[28], - mem_value_bytes[29], - mem_value_bytes[30], - mem_value_bytes[31], - ]) -} - -#[derive(Clone, Debug, PartialEq)] -pub struct CairoInstructionFlags { - pub opcode: CairoOpcode, - pub ap_update: ApUpdate, - pub pc_update: PcUpdate, - pub res_logic: ResLogic, - pub op1_src: Op1Src, - pub op0_reg: Op0Reg, - pub dst_reg: DstReg, -} - -impl CairoInstructionFlags { - /// Gives a bit trace representation of all flags. - /// Altough the flags can be interpreted as bits, they are - /// represented by field elements: Felt252::zero() for bit 0 and - /// Felt252::one() for bit 1. - #[rustfmt::skip] - pub fn to_bit_representation(&self) -> [Felt252; 16] { - let b0 = self.dst_reg.to_bit_representation(); - let b1 = self.op0_reg.to_bit_representation(); - let [b2, b3, b4] = self.op1_src.to_bit_representation(); - let [b5, b6] = self.res_logic.to_bit_representation(); - let [b7, b8, b9] = self.pc_update.to_bit_representation(); - let [b10, b11] = self.ap_update.to_bit_representation(); - let [b12, b13, b14] = self.opcode.to_bit_representation(); - - // In the paper, a little-endian format for the bit flags is - // mentioned. That is why they are arranged in this way (section 4.4 - // of the Cairo whitepaper - https://eprint.iacr.org/2021/1063.pdf) - [ - b0, // dst_reg bits - b1, // op0_reg bits - b4, b3, b2, // op1_src bits - b6, b5, // res_logic bits - b9, b8, b7, // pc_update bits - b11, b10, // ap_update bits - b14, b13, b12, // opcode bits - Felt252::zero(), - ] - } - - pub fn to_trace_representation(&self) -> [Felt252; 16] { - let bit_flags = self.to_bit_representation(); - to_bit_prefixes(bit_flags) - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum Op0Reg { - AP = 0, - FP = 1, -} - -impl Op0Reg { - pub fn to_bit_representation(&self) -> Felt252 { - match self { - Op0Reg::AP => Felt252::zero(), - Op0Reg::FP => Felt252::one(), - } - } -} - -impl TryFrom<&Felt252> for Op0Reg { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - - let op0_reg = ((flags & OP0_REG_MASK) >> OP0_REG_OFF) as u8; - - if op0_reg == 0 { - Ok(Op0Reg::AP) - } else if op0_reg == 1 { - Ok(Op0Reg::FP) - } else { - Err(InstructionDecodingError::InvalidOp0Reg) - } - } -} - -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum DstReg { - AP = 0, - FP = 1, -} -impl DstReg { - pub fn to_bit_representation(&self) -> Felt252 { - match self { - DstReg::AP => Felt252::zero(), - DstReg::FP => Felt252::one(), - } - } -} - -impl TryFrom<&Felt252> for DstReg { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let dst_reg = ((flags & DST_REG_MASK) >> DST_REG_OFF) as u8; - - if dst_reg == 0 { - Ok(DstReg::AP) - } else if dst_reg == 1 { - Ok(DstReg::FP) - } else { - Err(InstructionDecodingError::InvalidDstReg) - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Op1Src { - Op0 = 0, - Imm = 1, - FP = 2, - AP = 4, -} - -impl Op1Src { - pub fn to_bit_representation(&self) -> [Felt252; 3] { - match self { - Op1Src::Op0 => [Felt252::zero(), Felt252::zero(), Felt252::zero()], - Op1Src::Imm => [Felt252::zero(), Felt252::zero(), Felt252::one()], - Op1Src::FP => [Felt252::zero(), Felt252::one(), Felt252::zero()], - Op1Src::AP => [Felt252::one(), Felt252::zero(), Felt252::zero()], - } - } -} - -impl TryFrom<&Felt252> for Op1Src { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let op1_src = ((flags & OP1_SRC_MASK) >> OP1_SRC_OFF) as u8; - - match op1_src { - 0 => Ok(Op1Src::Op0), - 1 => Ok(Op1Src::Imm), - 2 => Ok(Op1Src::FP), - 4 => Ok(Op1Src::AP), - _ => Err(InstructionDecodingError::InvalidOp1Src), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ResLogic { - Op1 = 0, - Add = 1, - Mul = 2, - // TODO: Check if this is correct - Unconstrained, -} - -impl ResLogic { - pub fn to_bit_representation(&self) -> [Felt252; 2] { - match self { - ResLogic::Op1 => [Felt252::zero(), Felt252::zero()], - ResLogic::Add => [Felt252::zero(), Felt252::one()], - ResLogic::Mul => [Felt252::one(), Felt252::zero()], - ResLogic::Unconstrained => todo!(), - } - } -} - -impl TryFrom<&Felt252> for ResLogic { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let res_logic = ((flags & RES_LOGIC_MASK) >> RES_LOGIC_OFF) as u8; - - match res_logic { - 0 => Ok(ResLogic::Op1), - 1 => Ok(ResLogic::Add), - 2 => Ok(ResLogic::Mul), - // TODO: Check this is correct - 4 => Ok(ResLogic::Unconstrained), - _ => Err(InstructionDecodingError::InvalidResLogic), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum PcUpdate { - Regular = 0, - Jump = 1, - JumpRel = 2, - Jnz = 4, -} - -impl PcUpdate { - pub fn to_bit_representation(&self) -> [Felt252; 3] { - match self { - PcUpdate::Regular => [Felt252::zero(), Felt252::zero(), Felt252::zero()], - PcUpdate::Jump => [Felt252::zero(), Felt252::zero(), Felt252::one()], - PcUpdate::JumpRel => [Felt252::zero(), Felt252::one(), Felt252::zero()], - PcUpdate::Jnz => [Felt252::one(), Felt252::zero(), Felt252::zero()], - } - } -} - -impl TryFrom<&Felt252> for PcUpdate { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let pc_update = ((flags & PC_UPDATE_MASK) >> PC_UPDATE_OFF) as u8; - - match pc_update { - 0 => Ok(PcUpdate::Regular), - 1 => Ok(PcUpdate::Jump), - 2 => Ok(PcUpdate::JumpRel), - 4 => Ok(PcUpdate::Jnz), - _ => Err(InstructionDecodingError::InvalidPcUpdate), - } - } -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum ApUpdate { - Regular = 0, - Add = 1, - Add1 = 2, - // TODO: Check if this is correct - Add2, -} - -impl ApUpdate { - pub fn to_bit_representation(&self) -> [Felt252; 2] { - match self { - ApUpdate::Regular => [Felt252::zero(), Felt252::zero()], - ApUpdate::Add => [Felt252::zero(), Felt252::one()], - ApUpdate::Add1 => [Felt252::one(), Felt252::zero()], - ApUpdate::Add2 => todo!(), - } - } -} - -impl TryFrom<&Felt252> for ApUpdate { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let ap_update = ((flags & AP_UPDATE_MASK) >> AP_UPDATE_OFF) as u8; - - match ap_update { - 0 => Ok(ApUpdate::Regular), - 1 => Ok(ApUpdate::Add), - 2 => Ok(ApUpdate::Add1), - 4 => Ok(ApUpdate::Add2), - _ => Err(InstructionDecodingError::InvalidApUpdate), - } - } -} - -impl TryFrom<&Felt252> for CairoInstructionFlags { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - Ok(CairoInstructionFlags { - opcode: CairoOpcode::try_from(mem_value)?, - pc_update: PcUpdate::try_from(mem_value)?, - ap_update: ApUpdate::try_from(mem_value)?, - res_logic: ResLogic::try_from(mem_value)?, - op1_src: Op1Src::try_from(mem_value)?, - op0_reg: Op0Reg::try_from(mem_value)?, - dst_reg: DstReg::try_from(mem_value)?, - }) - } -} - -#[derive(Clone, Debug, PartialEq)] -pub enum CairoOpcode { - NOp = 0, - Call = 1, - Ret = 2, - AssertEq = 4, -} - -impl CairoOpcode { - pub fn to_bit_representation(&self) -> [Felt252; 3] { - match self { - CairoOpcode::NOp => [Felt252::zero(), Felt252::zero(), Felt252::zero()], - CairoOpcode::Call => [Felt252::zero(), Felt252::zero(), Felt252::one()], - CairoOpcode::Ret => [Felt252::zero(), Felt252::one(), Felt252::zero()], - CairoOpcode::AssertEq => [Felt252::one(), Felt252::zero(), Felt252::zero()], - } - } -} - -impl TryFrom<&Felt252> for CairoOpcode { - type Error = InstructionDecodingError; - - fn try_from(mem_value: &Felt252) -> Result { - let flags = aux_get_last_nim_of_field_element(mem_value) >> FLAGS_OFFSET; - let opcode = ((flags & OPCODE_MASK) >> OPCODE_OFF) as u8; - - match opcode { - 0 => Ok(CairoOpcode::NOp), - 1 => Ok(CairoOpcode::Call), - 2 => Ok(CairoOpcode::Ret), - 4 => Ok(CairoOpcode::AssertEq), - _ => Err(InstructionDecodingError::InvalidOpcode), - } - } -} - -fn to_bit_prefixes(bit_array: [Felt252; 16]) -> [Felt252; 16] { - let two = Felt252::from(2); - (0..bit_array.len()) - .map(|i| { - bit_array - .iter() - .enumerate() - .fold(Felt252::zero(), |acc, (j, flag_j)| { - let sum_term = if j < i { - Felt252::zero() - } else { - let exponent = j - i; - two.pow(exponent) * flag_j - }; - acc + sum_term - }) - }) - .collect::>() - .try_into() - .unwrap() -} - -#[cfg(test)] -mod tests { - use super::*; - /* - For the purpose of testing the decoding, we are going to use instructions obtained - directly from valid Cairo programs. The decoding shown here is obtained by inspecting - cairo-rs: - * Instruction A: 0x480680017fff8000 -> - Instruction { - off0: 0, - off1: -1, - off2: 1, - imm: Some(3618502680826344545094760424199446925499834509564823019178951359862461693953), - dst_register: AP, - op0_register: FP, - op1_addr: Imm, - res: Op1, - pc_update: Regular, - ap_update: Add1, - fp_update: Regular, - opcode: AssertEq - } - - * Instruction B: 0x1104800180018000 -> - Instruction { - off0: 0, - off1: 1, - off2: 1, - imm: Some(3618502788666131213697322783095070105623107215331596699973092056135872020275), - dst_register: AP, - op0_register: AP, - op1_addr: Imm, - res: Op1, - pc_update: JumpRel, - ap_update: Add2, - fp_update: APPlus2, - opcode: Call - } - - * Instruction C: 0x208b7fff7fff7fFelt252 -> - Instruction { - off0: -2, - off1: -1, - off2: -1, - imm: None, - dst_register: FP, - op0_register: FP, - op1_addr: FP, - res: Op1, - pc_update: Jump, - ap_update: Regular, - fp_update: Dst, - opcode: Ret - } - - * Instruction D: 0xa0680017fff7fff -> - Instruction { off0: -1, - off1: -1, - off2: 1, - imm: Some(7), - dst_register: AP, - op0_register: FP, - op1_addr: Imm, - res: Unconstrained, - pc_update: Jnz, - ap_update: Add1, - fp_update: Regular, - opcode: NOp - } - - * Instruction E: 0x48327ffc7ffa8000 -> - Instruction { - off0: 0, - off1: -6, - off2: -4, - imm: None, - dst_register: AP, - op0_register: FP, - op1_addr: AP, - res: Add, - pc_update: Regular, - ap_update: Add1, - fp_update: Regular, - opcode: AssertEq - } - - * Instruction F: 0x4000800d7ff07fff -> - Instruction { - off0: -1, - off1: -16, - off2: 13, - imm: None, - dst_register: AP, - op0_register: AP, - op1_addr: Op0, - res: Op1, - pc_update: Regular, - ap_update: Regular, - fp_update: Regular, - opcode: AssertEq - } - - * Instruction G: 0x48507fff7fFelt2528000 -> - Instruction { - off0: 0, - off1: -1, - off2: 1, - imm: Some(3), - dst_register: AP, - op0_register: AP, - op1_addr: Imm, - res: Mul, - pc_update: Regular, - ap_update: Add1, - fp_update: Regular, - opcode: AssertEq - } - - * Instruction H: 0x40780017fff7fff -> - Instruction { - off0: -1, - off1: -1, - off2: 1, - imm: Some(2), - dst_register: FP, - op0_register: FP, - op1_addr: Imm, - res: Op1, - pc_update: Regular, - ap_update: Add, - fp_update: Regular, - opcode: NOp - } - */ - - #[test] - fn assert_opcode_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(CairoOpcode::try_from(&value), Ok(CairoOpcode::AssertEq)); - } - - #[test] - fn call_opcode_flag_is_correct() { - // Instruction B - let value = Felt252::from(0x1104800180018000); - - assert_eq!(CairoOpcode::try_from(&value), Ok(CairoOpcode::Call)); - } - - #[test] - fn ret_opcode_flag_is_correct() { - // Instruction C - let value = Felt252::from(0x208b7fff7fff7ffe); - - assert_eq!(CairoOpcode::try_from(&value), Ok(CairoOpcode::Ret)); - } - - #[test] - fn nop_opcode_flag_is_correct() { - // Instruction D - let value = Felt252::from(0xa0680017fff7fff); - - assert_eq!(CairoOpcode::try_from(&value), Ok(CairoOpcode::NOp)); - } - - #[test] - fn regular_pc_update_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(PcUpdate::try_from(&value), Ok(PcUpdate::Regular)); - } - - #[test] - fn jump_pc_update_flag_is_correct() { - // Instruction C - let value = Felt252::from(0x208b7fff7fff7ffe); - - assert_eq!(PcUpdate::try_from(&value), Ok(PcUpdate::Jump)); - } - - #[test] - fn jumprel_pc_update_flag_is_correct() { - // Instruction B - let value = Felt252::from(0x1104800180018000); - - assert_eq!(PcUpdate::try_from(&value), Ok(PcUpdate::JumpRel)); - } - - #[test] - fn jnz_pc_update_flag_is_correct() { - // Instruction D - let value = Felt252::from(0xa0680017fff7fff); - - assert_eq!(PcUpdate::try_from(&value), Ok(PcUpdate::Jnz)); - } - - #[test] - fn regular_ap_update_flag_is_correct() { - // Instruction C - let value = Felt252::from(0x208b7fff7fff7ffe); - - assert_eq!(ApUpdate::try_from(&value), Ok(ApUpdate::Regular)); - } - - #[test] - fn add_ap_update_flag_is_correct() { - // Instruction H - let value = Felt252::from(0x40780017fff7fff); - - assert_eq!(ApUpdate::try_from(&value), Ok(ApUpdate::Add)); - } - - #[test] - fn add1_ap_update_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(ApUpdate::try_from(&value), Ok(ApUpdate::Add1)); - } - - #[test] - fn op1_res_logic_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(ResLogic::try_from(&value), Ok(ResLogic::Op1)); - } - - #[test] - fn add_res_logic_flag_is_correct() { - // Instruction E - let value = Felt252::from(0x48327ffc7ffa8000); - - assert_eq!(ResLogic::try_from(&value), Ok(ResLogic::Add)); - } - - #[test] - fn mul_res_logic_flag_is_correct() { - // Instruction G - let value = Felt252::from(0x48507fff7ffe8000); - - assert_eq!(ResLogic::try_from(&value), Ok(ResLogic::Mul)); - } - - #[test] - fn op0_op1_src_flag_is_correct() { - // Instruction F - let value = Felt252::from(0x4000800d7ff07fff); - - assert_eq!(Op1Src::try_from(&value), Ok(Op1Src::Op0)); - } - - #[test] - fn imm_op1_src_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(Op1Src::try_from(&value), Ok(Op1Src::Imm)); - } - - #[test] - fn ap_op1_src_flag_is_correct() { - // Instruction E - let value = Felt252::from(0x48327ffc7ffa8000); - - assert_eq!(Op1Src::try_from(&value), Ok(Op1Src::AP)); - } - - #[test] - fn fp_op1_src_flag_is_correct() { - // Instruction C - let value = Felt252::from(0x208b7fff7fff7ffe); - - assert_eq!(Op1Src::try_from(&value), Ok(Op1Src::FP)); - } - - #[test] - fn ap_op0_reg_flag_is_correct() { - // Instruction B - let value = Felt252::from(0x1104800180018000); - - assert_eq!(Op0Reg::try_from(&value), Ok(Op0Reg::AP)); - } - - #[test] - fn fp_op0_reg_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(Op0Reg::try_from(&value), Ok(Op0Reg::FP)); - } - - #[test] - fn ap_dst_reg_flag_is_correct() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - - assert_eq!(DstReg::try_from(&value), Ok(DstReg::AP)); - } - - #[test] - fn fp_dst_reg_flag_is_correct() { - // Instruction C - let value = Felt252::from(0x208b7fff7fff7ffe); - - assert_eq!(DstReg::try_from(&value), Ok(DstReg::FP)); - } - - #[test] - fn decoded_flags_of_assert_are_correct() { - let value = Felt252::from(0x400380837ffb8000); - let expected_flags = CairoInstructionFlags { - opcode: CairoOpcode::AssertEq, - pc_update: PcUpdate::Regular, - ap_update: ApUpdate::Regular, - op0_reg: Op0Reg::FP, - op1_src: Op1Src::Op0, - res_logic: ResLogic::Op1, - dst_reg: DstReg::FP, - }; - - let flags = CairoInstructionFlags::try_from(&value).unwrap(); - - assert_eq!(expected_flags, flags); - } - - #[test] - fn flags_bit_representation() { - // Bit-trace representation for each flag: - // DstReg::FP = 1 - // Op0Reg::FP = 1 - // Op1Src::Op0 = 0 0 0 - // ResLogic::Op1 = 0 0 - // PcUpdate::Regular = 0 0 0 - // ApUpdate::Regular = 0 0 - // CairoOpcode::AssertEq = 0 0 1 - - let flags = CairoInstructionFlags { - opcode: CairoOpcode::AssertEq, - pc_update: PcUpdate::Regular, - ap_update: ApUpdate::Regular, - op0_reg: Op0Reg::FP, - op1_src: Op1Src::Op0, - res_logic: ResLogic::Op1, - dst_reg: DstReg::FP, - }; - - #[rustfmt::skip] - let expected_representation = [ - Felt252::one(), - Felt252::one(), - Felt252::zero(), Felt252::zero(), Felt252::zero(), - Felt252::zero(), Felt252::zero(), - Felt252::zero(), Felt252::zero(), Felt252::zero(), - Felt252::zero(), Felt252::zero(), - Felt252::zero(), Felt252::zero(), Felt252::one(), - Felt252::zero(), - ]; - - let representation = flags.to_bit_representation(); - - assert_eq!(representation, expected_representation); - } - - #[test] - fn to_bit_prefixes_all_zeros_works() { - let bit_array = [Felt252::zero(); 16]; - - let result = to_bit_prefixes(bit_array); - let expected = [Felt252::zero(); 16]; - - assert_eq!(result, expected); - } - - #[test] - fn to_bit_prefixes_flag14_on_works() { - let mut bit_array = [Felt252::zero(); 16]; - // We turn on only the 14th bit, which is the most significant. - - bit_array[14] = Felt252::one(); - - let result = to_bit_prefixes(bit_array); - // The bit prefix value of f0 should be 16384, and the rest - // should be the bit prefixes of that number. - let expected: [Felt252; 16] = (0..16u32) - .map(|idx| { - if idx == 15 { - return Felt252::zero(); - } - Felt252::from(16384) / Felt252::from(2).pow(idx) - }) - .collect::>() - .try_into() - .unwrap(); - - assert_eq!(result, expected); - } -} diff --git a/provers/cairo/src/decode/instruction_offsets.rs b/provers/cairo/src/decode/instruction_offsets.rs deleted file mode 100644 index 09716045a..000000000 --- a/provers/cairo/src/decode/instruction_offsets.rs +++ /dev/null @@ -1,94 +0,0 @@ -use crate::Felt252; -use lambdaworks_math::field::{element::FieldElement, traits::IsField}; - -use super::instruction_flags::aux_get_last_nim_of_field_element; - -const OFF_DST_OFF: u32 = 0; -const OFF_OP0_OFF: u32 = 16; -const OFF_OP1_OFF: u32 = 32; -const OFFX_MASK: u64 = 0xFFFF; - -#[derive(Debug, PartialEq, Eq)] -pub struct InstructionOffsets { - pub off_dst: i32, - pub off_op0: i32, - pub off_op1: i32, -} - -impl InstructionOffsets { - pub fn new(mem_value: &Felt252) -> Self { - Self { - off_dst: Self::decode_offset(mem_value, OFF_DST_OFF), - off_op0: Self::decode_offset(mem_value, OFF_OP0_OFF), - off_op1: Self::decode_offset(mem_value, OFF_OP1_OFF), - } - } - - pub fn decode_offset(mem_value: &Felt252, instruction_offset: u32) -> i32 { - let offset = aux_get_last_nim_of_field_element(mem_value) >> instruction_offset & OFFX_MASK; - let vectorized_offset = offset.to_le_bytes(); - let aux = [ - vectorized_offset[0], - vectorized_offset[1].overflowing_sub(128).0, - ]; - i32::from(i16::from_le_bytes(aux)) - } - - pub fn to_trace_representation(&self) -> [FieldElement; 3] { - [ - to_unbiased_representation(self.off_dst), - to_unbiased_representation(self.off_op0), - to_unbiased_representation(self.off_op1), - ] - } -} - -/// Returns an unbiased representation of the number. This is applied to -/// instruction offsets as explained in section 9.4 of the Cairo whitepaper -/// to be in the range [0, 2^16). https://eprint.iacr.org/2021/1063.pdf -fn to_unbiased_representation(n: i32) -> FieldElement { - let b15 = 2u64.pow(15u32); - if n < 0 { - FieldElement::::from(b15 - n.unsigned_abs() as u64) - } else { - FieldElement::::from(n as u64 + b15) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn assert_opcode_flag_is_correct_1() { - // Instruction A - let value = Felt252::from(0x480680017fff8000); - let instruction_offsets = InstructionOffsets::new(&value); - - assert_eq!(instruction_offsets.off_dst, 0); - assert_eq!(instruction_offsets.off_op0, -1); - assert_eq!(instruction_offsets.off_op1, 1); - } - - #[test] - fn assert_opcode_flag_is_correct_2() { - // Instruction A - let value = Felt252::from(0x208b7fff7fff7ffe); - let instruction_offsets = InstructionOffsets::new(&value); - - assert_eq!(instruction_offsets.off_dst, -2); - assert_eq!(instruction_offsets.off_op0, -1); - assert_eq!(instruction_offsets.off_op1, -1); - } - - #[test] - fn assert_opcode_flag_is_correct_3() { - // Instruction A - let value = Felt252::from(0x48327ffc7ffa8000); - let instruction_offsets = InstructionOffsets::new(&value); - - assert_eq!(instruction_offsets.off_dst, 0); - assert_eq!(instruction_offsets.off_op0, -6); - assert_eq!(instruction_offsets.off_op1, -4); - } -} diff --git a/provers/cairo/src/decode/mod.rs b/provers/cairo/src/decode/mod.rs deleted file mode 100644 index 85d3adbaa..000000000 --- a/provers/cairo/src/decode/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod instruction_flags; -pub mod instruction_offsets; diff --git a/provers/cairo/src/errors.rs b/provers/cairo/src/errors.rs deleted file mode 100644 index 38d74937f..000000000 --- a/provers/cairo/src/errors.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[derive(Debug)] -pub enum CairoImportError { - /// Bytes should be a multiple of 24 for trace or 40 for memory - IncorrectNumberOfBytes, - FileError(std::io::Error), -} - -impl From for CairoImportError { - fn from(err: std::io::Error) -> CairoImportError { - CairoImportError::FileError(err) - } -} - -#[derive(Debug, PartialEq)] -pub enum InstructionDecodingError { - InvalidOpcode, - InvalidPcUpdate, - InvalidApUpdate, - InvalidResLogic, - InvalidOp1Src, - InvalidOp0Reg, - InvalidDstReg, - InstructionNotFound, -} diff --git a/provers/cairo/src/execution_trace.rs b/provers/cairo/src/execution_trace.rs deleted file mode 100644 index eece1d28d..000000000 --- a/provers/cairo/src/execution_trace.rs +++ /dev/null @@ -1,750 +0,0 @@ -use super::{ - cairo_mem::CairoMemory, - decode::{ - instruction_flags::{ - aux_get_last_nim_of_field_element, ApUpdate, CairoInstructionFlags, CairoOpcode, - DstReg, Op0Reg, Op1Src, PcUpdate, ResLogic, - }, - instruction_offsets::InstructionOffsets, - }, - register_states::RegisterStates, -}; -use crate::air::{EXTRA_ADDR, RC_HOLES}; -use crate::{ - air::{ - PublicInputs, FRAME_DST_ADDR, FRAME_OP0_ADDR, FRAME_OP1_ADDR, FRAME_PC, OFF_DST, OFF_OP0, - OFF_OP1, - }, - Felt252, -}; -use cairo_vm::without_std::collections::HashMap; -use lambdaworks_math::{ - field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, - unsigned_integer::element::UnsignedInteger, -}; -use stark_platinum_prover::trace::TraceTable; - -type CairoTraceTable = TraceTable; - -// MAIN TRACE LAYOUT -// ----------------------------------------------------------------------------------------- -// A. flags (16) : Decoded instruction flags -// B. res (1) : Res value -// C. mem_p (2) : Temporary memory pointers (ap and fp) -// D. mem_a (4) : Memory addresses (pc, dst_addr, op0_addr, op1_addr) -// E. mem_v (4) : Memory values (inst, dst, op0, op1) -// F. offsets (3) : (off_dst, off_op0, off_op1) -// G. derived (3) : (t0, t1, mul) -// -// A B C D E F G -// β”œxxxxxxxxxxxxxxxx|x|xx|xxxx|xxxx|xxx|xxx─ -// - -/// Builds the Cairo main trace (i.e. the trace without the auxiliary columns). -/// Builds the execution trace, fills the offset range-check holes and memory holes, adds -/// public memory dummy accesses (See section 9.8 of the Cairo whitepaper) and pads the result -/// so that it has a trace length equal to the closest power of two. -pub fn build_main_trace( - register_states: &RegisterStates, - memory: &CairoMemory, - public_input: &mut PublicInputs, -) -> CairoTraceTable { - let mut main_trace = build_cairo_execution_trace(register_states, memory); - - let mut address_cols = - main_trace.merge_columns(&[FRAME_PC, FRAME_DST_ADDR, FRAME_OP0_ADDR, FRAME_OP1_ADDR]); - - address_cols.sort_by_key(|x| x.representative()); - - let (rc_holes, rc_min, rc_max) = get_rc_holes(&main_trace, &[OFF_DST, OFF_OP0, OFF_OP1]); - - // this will avaluate to true if the public inputs weren't obtained from the run_program() function - if public_input.range_check_min.is_none() && public_input.range_check_max.is_none() { - public_input.range_check_min = Some(rc_min); - public_input.range_check_max = Some(rc_max); - } - fill_rc_holes(&mut main_trace, &rc_holes); - - let memory_holes = get_memory_holes(&address_cols, &public_input.public_memory); - - if !memory_holes.is_empty() { - fill_memory_holes(&mut main_trace, &memory_holes); - } - - add_pub_memory_dummy_accesses( - &mut main_trace, - public_input.public_memory.len(), - memory_holes.len(), - ); - - let trace_len_next_power_of_two = main_trace.n_rows().next_power_of_two(); - let padding_len = trace_len_next_power_of_two - main_trace.n_rows(); - main_trace.pad_with_last_row(padding_len); - - main_trace -} - -/// Artificial `(0, 0)` dummy memory accesses must be added for the public memory. -/// See section 9.8 of the Cairo whitepaper. -fn add_pub_memory_dummy_accesses( - main_trace: &mut CairoTraceTable, - pub_memory_len: usize, - last_memory_hole_idx: usize, -) { - for i in 0..pub_memory_len { - main_trace.set_or_extend(last_memory_hole_idx + i, EXTRA_ADDR, &Felt252::zero()); - } -} - -/// Gets holes from the range-checked columns. These holes must be filled for the -/// permutation range-checks, as can be read in section 9.9 of the Cairo whitepaper. -/// Receives the trace and the indexes of the range-checked columns. -/// Outputs the holes that must be filled to make the range continuous and the extreme -/// values rc_min and rc_max, corresponding to the minimum and maximum values of the range. -/// NOTE: These extreme values should be received as public inputs in the future and not -/// calculated here. -fn get_rc_holes(trace: &CairoTraceTable, columns_indices: &[usize]) -> (Vec, u16, u16) { - let offset_columns = trace.merge_columns(columns_indices); - - let mut sorted_offset_representatives: Vec = offset_columns - .iter() - .map(|x| x.representative().into()) - .collect(); - sorted_offset_representatives.sort(); - - let mut all_missing_values: Vec = Vec::new(); - - for window in sorted_offset_representatives.windows(2) { - if window[1] != window[0] { - let mut missing_range: Vec<_> = ((window[0] + 1)..window[1]) - .map(|x| Felt252::from(x as u64)) - .collect(); - all_missing_values.append(&mut missing_range); - } - } - - let multiple_of_three_padding = - ((all_missing_values.len() + 2) / 3) * 3 - all_missing_values.len(); - let padding_element = Felt252::from(*sorted_offset_representatives.last().unwrap() as u64); - all_missing_values.append(&mut vec![padding_element; multiple_of_three_padding]); - - ( - all_missing_values, - sorted_offset_representatives[0], - sorted_offset_representatives.last().cloned().unwrap(), - ) -} - -/// Fills holes found in the range-checked columns. -fn fill_rc_holes(trace: &mut CairoTraceTable, holes: &[Felt252]) { - holes.iter().enumerate().for_each(|(i, hole)| { - trace.set_or_extend(i, RC_HOLES, hole); - }); - - // Fill the rest of the RC_HOLES column to avoid inexistent zeros - let mut offsets = trace.merge_columns(&[OFF_DST, OFF_OP0, OFF_OP1, RC_HOLES]); - - offsets.sort_by_key(|x| x.representative()); - let greatest_offset = offsets.last().unwrap(); - (holes.len()..trace.n_rows()).for_each(|i| { - trace.set_or_extend(i, RC_HOLES, greatest_offset); - }); -} - -/// Get memory holes from accessed addresses. These memory holes appear -/// as a consequence of interaction with builtins. -/// Returns a vector of addresses that were not present in the input vector (holes) -/// -/// # Arguments -/// -/// * `sorted_addrs` - Vector of sorted memory addresses. -/// * `pub_memory` - The public memory of the executed program. -fn get_memory_holes( - sorted_addrs: &[Felt252], - pub_memory: &HashMap, -) -> Vec { - let mut memory_holes = Vec::new(); - let mut prev_addr = &sorted_addrs[0]; - - for addr in sorted_addrs.iter() { - let addr_diff = addr - prev_addr; - - // If the candidate memory hole has an address belonging to the program segment (public - // memory), that is not accounted here since public memory is added in a posterior step of - // the protocol. - if addr_diff != Felt252::one() && addr_diff != Felt252::zero() { - let mut hole_addr = prev_addr + Felt252::one(); - - while hole_addr.representative() < addr.representative() { - if !pub_memory.contains_key(&hole_addr) { - memory_holes.push(hole_addr); - } - hole_addr += Felt252::one(); - } - } - prev_addr = addr; - } - - memory_holes -} - -/// Fill memory holes in the extra address column of the trace with the missing addresses. -fn fill_memory_holes(trace: &mut CairoTraceTable, memory_holes: &[Felt252]) { - memory_holes.iter().enumerate().for_each(|(i, hole)| { - trace.set_or_extend(i, EXTRA_ADDR, hole); - }); -} - -/// Receives the raw Cairo trace and memory as outputted from the Cairo VM and returns -/// the trace table used to Felt252ed the Cairo STARK prover. -/// The constraints of the Cairo AIR are defined over this trace rather than the raw trace -/// obtained from the Cairo VM, this is why this function is needed. -pub fn build_cairo_execution_trace( - register_states: &RegisterStates, - memory: &CairoMemory, -) -> CairoTraceTable { - let n_steps = register_states.steps(); - - // Instruction flags and offsets are decoded from the raw instructions and represented - // by the CairoInstructionFlags and InstructionOffsets as an intermediate representation - let (flags, offsets): (Vec, Vec) = register_states - .flags_and_offsets(memory) - .unwrap() - .into_iter() - .unzip(); - - // dst, op0, op1 and res are computed from flags and offsets - let (dst_addrs, mut dsts): (Vec, Vec) = - compute_dst(&flags, &offsets, register_states, memory); - let (op0_addrs, mut op0s): (Vec, Vec) = - compute_op0(&flags, &offsets, register_states, memory); - let (op1_addrs, op1s): (Vec, Vec) = - compute_op1(&flags, &offsets, register_states, memory, &op0s); - let mut res = compute_res(&flags, &op0s, &op1s, &dsts); - - // In some cases op0, dst or res may need to be updated from the already calculated values - update_values(&flags, register_states, &mut op0s, &mut dsts, &mut res); - - // Flags and offsets are transformed to a bit representation. This is needed since - // the flag constraints of the Cairo AIR are defined over bit representations of these - let trace_repr_flags: Vec<[Felt252; 16]> = flags - .iter() - .map(CairoInstructionFlags::to_trace_representation) - .collect(); - let trace_repr_offsets: Vec<[Felt252; 3]> = offsets - .iter() - .map(InstructionOffsets::to_trace_representation) - .collect(); - - // ap, fp, pc and instruction columns are computed - let aps: Vec = register_states - .rows - .iter() - .map(|t| Felt252::from(t.ap)) - .collect(); - let fps: Vec = register_states - .rows - .iter() - .map(|t| Felt252::from(t.fp)) - .collect(); - let pcs: Vec = register_states - .rows - .iter() - .map(|t| Felt252::from(t.pc)) - .collect(); - let instructions: Vec = register_states - .rows - .iter() - .map(|t| *memory.get(&t.pc).unwrap()) - .collect(); - - // t0, t1 and mul derived values are constructed. For details reFelt252r to - // section 9.1 of the Cairo whitepaper - let two = Felt252::from(2); - let t0: Vec = trace_repr_flags - .iter() - .zip(&dsts) - .map(|(repr_flags, dst)| (repr_flags[9] - two * repr_flags[10]) * dst) - .collect(); - let t1: Vec = t0.iter().zip(&res).map(|(t, r)| t * r).collect(); - let mul: Vec = op0s.iter().zip(&op1s).map(|(op0, op1)| op0 * op1).collect(); - - // A structure change of the flags and offsets representations to fit into the arguments - // expected by the TraceTable constructor. A vector of columns of the representations - // is obtained from the rows representation. - let trace_repr_flags = rows_to_cols(&trace_repr_flags); - let trace_repr_offsets = rows_to_cols(&trace_repr_offsets); - - let extra_addrs = vec![Felt252::zero(); n_steps]; - let extra_vals = extra_addrs.clone(); - let rc_holes = extra_addrs.clone(); - - // Build Cairo trace columns to instantiate TraceTable struct as defined in the trace layout - let mut trace_cols: Vec> = Vec::new(); - (0..trace_repr_flags.len()).for_each(|n| trace_cols.push(trace_repr_flags[n].clone())); - trace_cols.push(res); - trace_cols.push(aps); - trace_cols.push(fps); - trace_cols.push(pcs); - trace_cols.push(dst_addrs); - trace_cols.push(op0_addrs); - trace_cols.push(op1_addrs); - trace_cols.push(instructions); - trace_cols.push(dsts); - trace_cols.push(op0s); - trace_cols.push(op1s); - (0..trace_repr_offsets.len()).for_each(|n| trace_cols.push(trace_repr_offsets[n].clone())); - trace_cols.push(t0); - trace_cols.push(t1); - trace_cols.push(mul); - trace_cols.push(extra_addrs); - trace_cols.push(extra_vals); - trace_cols.push(rc_holes); - - TraceTable::from_columns_main(trace_cols, 1) -} - -/// Returns the vector of res values. -fn compute_res( - flags: &[CairoInstructionFlags], - op0s: &[Felt252], - op1s: &[Felt252], - dsts: &[Felt252], -) -> Vec { - /* - Cairo whitepaper, page 33 - https://eprint.iacr.org/2021/1063.pdf - # Compute res. - if pc_update == 4: - if res_logic == 0 && opcode == 0 && ap_update != 1: - res = Unused - else: - Undefined Behavior - else if pc_update = 0, 1 or 2: - switch res_logic: - case 0: res = op1 - case 1: res = op0 + op1 - case 2: res = op0 * op1 - default: Undefined Behavior - else: Undefined Behavior - */ - flags - .iter() - .zip(op0s) - .zip(op1s) - .zip(dsts) - .map(|(((f, op0), op1), dst)| { - match f.pc_update { - PcUpdate::Jnz => { - match (&f.res_logic, &f.opcode, &f.ap_update) { - ( - ResLogic::Op1, - CairoOpcode::NOp, - ApUpdate::Regular | ApUpdate::Add1 | ApUpdate::Add2, - ) => { - // In a `jnz` instruction, res is not used, so it is used - // to hold the value v = dst^(-1) as an optimization. - // This is important for the calculation of the `t1` virtual column - // values later on. - // See section 9.5 of the Cairo whitepaper, page 53. - if dst == &Felt252::zero() { - *dst - } else { - dst.inv().unwrap() - } - } - _ => { - panic!("Undefined Behavior"); - } - } - } - PcUpdate::Regular | PcUpdate::Jump | PcUpdate::JumpRel => match f.res_logic { - ResLogic::Op1 => *op1, - ResLogic::Add => op0 + op1, - ResLogic::Mul => op0 * op1, - ResLogic::Unconstrained => { - panic!("Undefined Behavior"); - } - }, - } - }) - .collect() -} - -/// Returns the vector of: -/// - dst_addrs -/// - dsts -fn compute_dst( - flags: &[CairoInstructionFlags], - offsets: &[InstructionOffsets], - register_states: &RegisterStates, - memory: &CairoMemory, -) -> (Vec, Vec) { - /* Cairo whitepaper, page 33 - https://eprint.iacr.org/2021/1063.pdf - - # Compute dst - if dst_reg == 0: - dst = m(ap + offdst) - else: - dst = m(fp + offdst) - */ - flags - .iter() - .zip(offsets) - .zip(register_states.rows.iter()) - .map(|((f, o), t)| match f.dst_reg { - DstReg::AP => { - let addr = t.ap.checked_add_signed(o.off_dst.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - DstReg::FP => { - let addr = t.fp.checked_add_signed(o.off_dst.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - }) - .unzip() -} - -/// Returns the vector of: -/// - op0_addrs -/// - op0s -fn compute_op0( - flags: &[CairoInstructionFlags], - offsets: &[InstructionOffsets], - register_states: &RegisterStates, - memory: &CairoMemory, -) -> (Vec, Vec) { - /* Cairo whitepaper, page 33 - https://eprint.iacr.org/2021/1063.pdf - - # Compute op0. - if op0_reg == 0: - op0 = m(ap + offop0) - else: - op0 = m(fp + offop0) - */ - flags - .iter() - .zip(offsets) - .zip(register_states.rows.iter()) - .map(|((f, o), t)| match f.op0_reg { - Op0Reg::AP => { - let addr = t.ap.checked_add_signed(o.off_op0.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - Op0Reg::FP => { - let addr = t.fp.checked_add_signed(o.off_op0.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - }) - .unzip() -} - -/// Returns the vector of: -/// - op1_addrs -/// - op1s -fn compute_op1( - flags: &[CairoInstructionFlags], - offsets: &[InstructionOffsets], - register_states: &RegisterStates, - memory: &CairoMemory, - op0s: &[Felt252], -) -> (Vec, Vec) { - /* Cairo whitepaper, page 33 - https://eprint.iacr.org/2021/1063.pdf - # Compute op1 and instruction_size. - switch op1_src: - case 0: - instruction_size = 1 - op1 = m(op0 + offop1) - case 1: - instruction_size = 2 - op1 = m(pc + offop1) - # If offop1 = 1, we have op1 = immediate_value. - case 2: - instruction_size = 1 - op1 = m(fp + offop1) - case 4: - instruction_size = 1 - op1 = m(ap + offop1) - default: - Undefined Behavior - */ - flags - .iter() - .zip(offsets) - .zip(op0s) - .zip(register_states.rows.iter()) - .map(|(((flag, offset), op0), trace_state)| match flag.op1_src { - Op1Src::Op0 => { - let addr = aux_get_last_nim_of_field_element(op0) - .checked_add_signed(offset.off_op1.into()) - .unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - Op1Src::Imm => { - let pc = trace_state.pc; - let addr = pc.checked_add_signed(offset.off_op1.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - Op1Src::AP => { - let ap = trace_state.ap; - let addr = ap.checked_add_signed(offset.off_op1.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - Op1Src::FP => { - let fp = trace_state.fp; - let addr = fp.checked_add_signed(offset.off_op1.into()).unwrap(); - (Felt252::from(addr), *memory.get(&addr).unwrap()) - } - }) - .unzip() -} - -/// Depending on the instruction opcodes, some values should be updated. -/// This function updates op0s, dst, res in place when the conditions hold. -fn update_values( - flags: &[CairoInstructionFlags], - register_states: &RegisterStates, - op0s: &mut [Felt252], - dst: &mut [Felt252], - res: &mut [Felt252], -) { - for (i, f) in flags.iter().enumerate() { - if f.opcode == CairoOpcode::Call { - let instruction_size = if flags[i].op1_src == Op1Src::Imm { - 2 - } else { - 1 - }; - op0s[i] = (register_states.rows[i].pc + instruction_size).into(); - dst[i] = register_states.rows[i].fp.into(); - } else if f.opcode == CairoOpcode::AssertEq { - res[i] = dst[i]; - } - } -} - -/// Utility function to change from a rows representation to a columns -/// representation of a slice of arrays. -fn rows_to_cols(rows: &[[Felt252; N]]) -> Vec> { - let n_cols = rows[0].len(); - - (0..n_cols) - .map(|col_idx| { - rows.iter() - .map(|elem| elem[col_idx]) - .collect::>() - }) - .collect::>>() -} - -// NOTE: Leaving this function despite not being used anywhere. It could be useful once -// we implement layouts with the range-check builtin. -#[allow(dead_code)] -fn decompose_rc_values_into_trace_columns(rc_values: &[&Felt252]) -> [Vec; 8] { - let mask = UnsignedInteger::from_hex("FFFF").unwrap(); - let mut rc_base_types: Vec> = - rc_values.iter().map(|x| x.representative()).collect(); - - let mut decomposition_columns: Vec> = Vec::new(); - - for _ in 0..8 { - decomposition_columns.push( - rc_base_types - .iter() - .map(|&x| Felt252::from(&(x & mask))) - .collect(), - ); - - rc_base_types = rc_base_types.iter().map(|&x| x >> 16).collect(); - } - - // This can't fail since we have 8 pushes - decomposition_columns.try_into().unwrap() -} - -#[cfg(test)] -mod test { - use crate::air::EXTRA_VAL; - - use super::*; - use lambdaworks_math::field::element::FieldElement; - use stark_platinum_prover::table::Table; - - #[test] - fn test_rc_decompose() { - let fifteen = Felt252::from_hex("000F000F000F000F000F000F000F000F").unwrap(); - let sixteen = Felt252::from_hex("00100010001000100010001000100010").unwrap(); - let one_two_three = Felt252::from_hex("00010002000300040005000600070008").unwrap(); - - let decomposition_columns = - decompose_rc_values_into_trace_columns(&[&fifteen, &sixteen, &one_two_three]); - - for row in &decomposition_columns { - assert_eq!(row[0], Felt252::from_hex("F").unwrap()); - assert_eq!(row[1], Felt252::from_hex("10").unwrap()); - } - - assert_eq!(decomposition_columns[0][2], Felt252::from_hex("8").unwrap()); - assert_eq!(decomposition_columns[1][2], Felt252::from_hex("7").unwrap()); - assert_eq!(decomposition_columns[2][2], Felt252::from_hex("6").unwrap()); - assert_eq!(decomposition_columns[3][2], Felt252::from_hex("5").unwrap()); - assert_eq!(decomposition_columns[4][2], Felt252::from_hex("4").unwrap()); - assert_eq!(decomposition_columns[5][2], Felt252::from_hex("3").unwrap()); - assert_eq!(decomposition_columns[6][2], Felt252::from_hex("2").unwrap()); - assert_eq!(decomposition_columns[7][2], Felt252::from_hex("1").unwrap()); - } - - #[test] - fn test_fill_range_check_values() { - let columns = vec![ - vec![FieldElement::from(1); 3], - vec![FieldElement::from(4); 3], - vec![FieldElement::from(7); 3], - ]; - let expected_col = vec![ - FieldElement::from(2), - FieldElement::from(3), - FieldElement::from(5), - FieldElement::from(6), - FieldElement::from(7), - FieldElement::from(7), - ]; - let table = TraceTable::::from_columns(columns, 3, 1); - - let (col, rc_min, rc_max) = get_rc_holes(&table, &[0, 1, 2]); - assert_eq!(col, expected_col); - assert_eq!(rc_min, 1); - assert_eq!(rc_max, 7); - } - - #[test] - fn test_add_missing_values_to_rc_holes_column() { - let mut row = vec![Felt252::from(5); 36]; - row[35] = Felt252::zero(); - let data = row.repeat(8); - let table = Table::new(data, 36); - - let mut main_trace = TraceTable:: { - table, - num_main_columns: 36, - num_aux_columns: 23, - step_size: 1, - }; - - let rc_holes = vec![ - Felt252::from(1), - Felt252::from(2), - Felt252::from(3), - Felt252::from(4), - Felt252::from(5), - Felt252::from(6), - ]; - - fill_rc_holes(&mut main_trace, &rc_holes); - - let expected_rc_holes_column = vec![ - Felt252::from(1), - Felt252::from(2), - Felt252::from(3), - Felt252::from(4), - Felt252::from(5), - Felt252::from(6), - Felt252::from(6), - Felt252::from(6), - ]; - - let rc_holes_column = main_trace.columns()[35].clone(); - - assert_eq!(expected_rc_holes_column, rc_holes_column); - } - - #[test] - fn test_get_memory_holes_empty_pub_memory() { - // We construct a sorted addresses list [1, 2, 3, 6, 7, 8, 9, 13, 14, 15], and - // an empty public memory. This way, any holes present between - // the min and max addresses should be returned by the function. - let mut addrs: Vec = (1..4).map(Felt252::from).collect(); - let addrs_extension: Vec = (6..10).map(Felt252::from).collect(); - addrs.extend_from_slice(&addrs_extension); - let addrs_extension: Vec = (13..16).map(Felt252::from).collect(); - addrs.extend_from_slice(&addrs_extension); - let pub_memory = HashMap::new(); - - let expected_memory_holes = vec![ - Felt252::from(4), - Felt252::from(5), - Felt252::from(10), - Felt252::from(11), - Felt252::from(12), - ]; - let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory); - - assert_eq!(expected_memory_holes, calculated_memory_holes); - } - - #[test] - fn test_get_memory_holes_inside_program_section() { - // We construct a sorted addresses list [1, 2, 3, 8, 9] and we - // set public memory from address 1 to 9. Since all the holes will be inside the - // program segment (meaning from addresses 1 to 9), the function - // should not return any of them. - let mut addrs: Vec = (1..4).map(Felt252::from).collect(); - let addrs_extension: Vec = (8..10).map(Felt252::from).collect(); - addrs.extend_from_slice(&addrs_extension); - - let mut pub_memory = HashMap::new(); - (1..=9).for_each(|k| { - let addr = Felt252::from(k); - pub_memory.insert(addr, addr * Felt252::from(2)); - }); - - let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory); - let expected_memory_holes: Vec = Vec::new(); - - assert_eq!(expected_memory_holes, calculated_memory_holes); - } - - #[test] - fn test_get_memory_holes_outside_program_section() { - // We construct a sorted addresses list [1, 2, 3, 8, 9] and we - // set public memory from addresses 1 to 6. The holes found inside the program section, - // i.e. in the address range between 1 to 6, should not be returned. - // So addresses 4, 5 and 6 will no be returned, only address 7. - let mut addrs: Vec = (1..4).map(Felt252::from).collect(); - let addrs_extension: Vec = (8..10).map(Felt252::from).collect(); - addrs.extend_from_slice(&addrs_extension); - - let mut pub_memory = HashMap::new(); - (1..=6).for_each(|k| { - let addr = Felt252::from(k); - pub_memory.insert(addr, addr * Felt252::from(2)); - }); - - let calculated_memory_holes = get_memory_holes(&addrs, &pub_memory); - let expected_memory_holes = vec![Felt252::from(7)]; - - assert_eq!(expected_memory_holes, calculated_memory_holes); - } - - #[test] - fn test_fill_memory_holes() { - const TRACE_COL_LEN: usize = 2; - const NUM_TRACE_COLS: usize = EXTRA_VAL + 1; - - let mut trace_cols = vec![vec![Felt252::zero(); TRACE_COL_LEN]; NUM_TRACE_COLS]; - trace_cols[FRAME_PC][0] = Felt252::one(); - trace_cols[FRAME_DST_ADDR][0] = Felt252::from(2); - trace_cols[FRAME_OP0_ADDR][0] = Felt252::from(3); - trace_cols[FRAME_OP1_ADDR][0] = Felt252::from(5); - trace_cols[FRAME_PC][1] = Felt252::from(6); - trace_cols[FRAME_DST_ADDR][1] = Felt252::from(9); - trace_cols[FRAME_OP0_ADDR][1] = Felt252::from(10); - trace_cols[FRAME_OP1_ADDR][1] = Felt252::from(11); - let mut trace = TraceTable::from_columns(trace_cols, 2, 1); - - let memory_holes = vec![Felt252::from(4), Felt252::from(7), Felt252::from(8)]; - fill_memory_holes(&mut trace, &memory_holes); - - let extra_addr = &trace.columns()[EXTRA_ADDR]; - assert_eq!(extra_addr, &memory_holes); - } -} diff --git a/provers/cairo/src/lib.rs b/provers/cairo/src/lib.rs deleted file mode 100644 index 54384a63c..000000000 --- a/provers/cairo/src/lib.rs +++ /dev/null @@ -1,22 +0,0 @@ -use lambdaworks_math::field::{ - element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, -}; - -pub mod air; -pub mod cairo_layout; -pub mod cairo_mem; -pub mod decode; -pub mod errors; -pub mod execution_trace; -pub mod register_states; -pub mod runner; -pub mod transition_constraints; - -#[cfg(test)] -pub mod tests; - -#[cfg(feature = "wasm")] -pub mod wasm_wrappers; - -pub type PrimeField = Stark252PrimeField; -pub type Felt252 = FieldElement; diff --git a/provers/cairo/src/main.rs b/provers/cairo/src/main.rs deleted file mode 100644 index b64a51f26..000000000 --- a/provers/cairo/src/main.rs +++ /dev/null @@ -1,350 +0,0 @@ -use cairo_platinum_prover::air::{generate_cairo_proof, verify_cairo_proof, PublicInputs}; -use cairo_platinum_prover::cairo_layout::CairoLayout; -use cairo_platinum_prover::runner::run::generate_prover_args; -use cairo_platinum_prover::runner::run::generate_prover_args_from_trace; -use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; -use stark_platinum_prover::proof::options::{ProofOptions, SecurityLevel}; -use stark_platinum_prover::proof::stark::StarkProof; -mod commands; -use clap::Parser; - -use std::env; -use std::fs::File; -use std::io::{Error, ErrorKind}; -use std::process::{Command, Stdio}; -use std::time::Instant; - -/// Get current directory and return it as a String -fn get_root_dir() -> Result { - let path_buf = env::current_dir()?.canonicalize()?; - if let Some(path) = path_buf.to_str() { - return Ok(path.to_string()); - } - - Err(Error::new(ErrorKind::NotFound, "not found")) -} - -/// Attemps to compile the Cairo program with `cairo-compile` -/// and then save it to the desired path. -/// Returns `Ok` on success else returns `Error` -fn cairo_compile(program_path: &String, out_file_path: &String) -> Result<(), Error> { - let out_file = File::create(out_file_path)?; - - match Command::new("cairo-compile") - .arg("--proof_mode") - .arg(program_path) - .stderr(Stdio::null()) - .stdout(out_file) - .spawn() - { - Ok(mut child) => { - // wait for spawned proccess to finish - match child.wait() { - Ok(_) => Ok(()), - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } -} - -/// Attemps to compile the Cairo program with `docker` -/// and then save it to the desired path. -/// Returns `Ok` on success else returns `Error` -fn docker_compile(program_path: &String, out_file_path: &String) -> Result<(), Error> { - let out_file = File::create(out_file_path)?; - let root_dir = get_root_dir()?; - match Command::new("docker") - .arg("run") - .arg("--rm") - .arg("-v") - .arg(format!("{}/:/pwd", root_dir)) - .arg("cairo") - .arg("--proof_mode") - .arg(format!("/pwd/{}", program_path)) - .stderr(Stdio::null()) - .stdout(out_file) - .spawn() - { - Ok(mut child) => { - // wait for spawned proccess to finish - match child.wait() { - Ok(status) => match status.code() { - Some(0) => Ok(()), // exit success - _ => Err(Error::new( - ErrorKind::Other, - "File provided is not a Cairo uncompiled", - )), - }, - Err(err) => Err(err), - } - } - Err(err) => Err(err), - } -} - -/// Attemps to compile the Cairo program -/// with either `cairo-compile` or `docker`` -fn try_compile(program_path: &String, out_file_path: &String) -> Result<(), Error> { - if !program_path.contains(".cairo") { - return Err(Error::new( - ErrorKind::Other, - "Provided file is not a Cairo source file", - )); - } - - if cairo_compile(program_path, out_file_path).is_ok() - || docker_compile(program_path, out_file_path).is_ok() - { - Ok(()) - } else { - Err(Error::new( - ErrorKind::Other, - "Failed to compile cairo program, neither cairo-compile nor docker found", - )) - } -} - -fn generate_proof( - input_path: &String, - proof_options: &ProofOptions, -) -> Option<( - StarkProof, - PublicInputs, -)> { - let timer = Instant::now(); - - let Ok(program_content) = std::fs::read(input_path) else { - eprintln!("Error opening {input_path} file"); - return None; - }; - - // FIXME: We should set this through the CLI in the future - let layout = CairoLayout::Plain; - - let Ok((main_trace, pub_inputs)) = generate_prover_args(&program_content, layout) else { - eprintln!("Error generating prover args"); - return None; - }; - - println!(" Time spent: {:?} \n", timer.elapsed()); - - let timer = Instant::now(); - println!("Making proof ..."); - let proof = match generate_cairo_proof(&main_trace, &pub_inputs, proof_options) { - Ok(p) => p, - Err(err) => { - eprintln!("Error generating proof: {:?}", err); - return None; - } - }; - - println!(" Time spent in proving: {:?} \n", timer.elapsed()); - - Some((proof, pub_inputs)) -} - -fn generate_proof_from_trace( - trace_bin_path: &str, - memory_bin_path: &str, - proof_options: &ProofOptions, -) -> Option<( - StarkProof, - PublicInputs, -)> { - // ## Generating the prover args - let timer = Instant::now(); - let Ok((main_trace, pub_inputs)) = - generate_prover_args_from_trace(trace_bin_path, memory_bin_path) - else { - eprintln!("Error generating prover args"); - return None; - }; - println!(" Time spent: {:?} \n", timer.elapsed()); - - // ## Prove - let timer = Instant::now(); - println!("Making proof ..."); - let proof = match generate_cairo_proof(&main_trace, &pub_inputs, proof_options) { - Ok(p) => p, - Err(err) => { - eprintln!("Error generating proof: {:?}", err); - return None; - } - }; - println!(" Time spent in proving: {:?} \n", timer.elapsed()); - - Some((proof, pub_inputs)) -} - -fn verify_proof( - proof: StarkProof, - pub_inputs: PublicInputs, - proof_options: &ProofOptions, -) -> bool { - let timer = Instant::now(); - - println!("Verifying ..."); - let proof_verified = verify_cairo_proof(&proof, &pub_inputs, proof_options); - println!(" Time spent in verifying: {:?} \n", timer.elapsed()); - - if proof_verified { - println!("Verification succeeded"); - } else { - println!("Verification failed"); - } - - proof_verified -} - -fn write_proof( - proof: StarkProof, - pub_inputs: PublicInputs, - proof_path: String, -) { - let mut bytes = vec![]; - let proof_bytes: Vec = - bincode::serde::encode_to_vec(proof, bincode::config::standard()).unwrap(); - - let pub_inputs_bytes: Vec = - bincode::serde::encode_to_vec(&pub_inputs, bincode::config::standard()).unwrap(); - - // This should be reworked - // Public inputs shouldn't be stored in the proof if the verifier wants to check them - - // An u32 is enough for storing proofs up to 32 GiB - // They shouldn't exceed the order of kbs - // Reading an usize leads to problem in WASM (32 bit vs 64 bit architecture) - - bytes.extend((proof_bytes.len() as u32).to_le_bytes()); - bytes.extend(proof_bytes); - bytes.extend(pub_inputs_bytes); - - let Ok(()) = std::fs::write(&proof_path, bytes) else { - eprintln!("Error writing proof to file: {}", &proof_path); - return; - }; - - println!("Proof written to {}", &proof_path); -} - -fn main() { - let proof_options = ProofOptions::new_secure(SecurityLevel::Conjecturable100Bits, 3); - let args: commands::ProverArgs = commands::ProverArgs::parse(); - match args.entity { - commands::ProverEntity::Compile(args) => { - let out_file_path = args.program_path.replace(".cairo", ".json"); - if let Err(err) = try_compile(&args.program_path, &out_file_path) { - eprintln!("{}", err); - } else { - println!("Compiled cairo program"); - } - } - commands::ProverEntity::RunAndProve(args) => { - // verify input file is .cairo - if args.program_path.contains(".cairo") { - eprintln!("\nYou are trying to prove a non compiled Cairo program. Please compile it before sending it to the prover.\n"); - return; - } - - let Some((proof, pub_inputs)) = generate_proof(&args.program_path, &proof_options) - else { - return; - }; - - write_proof(proof, pub_inputs, args.proof_path); - } - commands::ProverEntity::Prove(args) => { - let Some((proof, pub_inputs)) = generate_proof_from_trace( - &args.trace_bin_path, - &args.memory_bin_path, - &proof_options, - ) else { - return; - }; - - write_proof(proof, pub_inputs, args.proof_path); - } - commands::ProverEntity::Verify(args) => { - let Ok(program_content) = std::fs::read(&args.proof_path) else { - eprintln!("Error opening {} file", args.proof_path); - return; - }; - let mut bytes = program_content.as_slice(); - if bytes.len() < 8 { - eprintln!("Error reading proof from file: {}", args.proof_path); - return; - } - - // Proof len was stored as an u32, 4u8 needs to be read - let proof_len = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize; - - bytes = &bytes[4..]; - if bytes.len() < proof_len { - eprintln!("Error reading proof from file: {}", args.proof_path); - return; - } - - let Ok((proof, _)) = bincode::serde::decode_from_slice( - &bytes[0..proof_len], - bincode::config::standard(), - ) else { - println!("Error reading proof from file: {}", args.proof_path); - return; - }; - bytes = &bytes[proof_len..]; - - let Ok((pub_inputs, _)) = - bincode::serde::decode_from_slice(bytes, bincode::config::standard()) - else { - println!("Error reading proof from file: {}", args.proof_path); - return; - }; - - verify_proof(proof, pub_inputs, &proof_options); - } - commands::ProverEntity::ProveAndVerify(args) => { - if args.program_path.contains(".cairo") { - eprintln!("\nYou are trying to prove a non compiled Cairo program. Please compile it before sending it to the prover.\n"); - return; - } - - let Some((proof, pub_inputs)) = generate_proof(&args.program_path, &proof_options) - else { - return; - }; - verify_proof(proof, pub_inputs, &proof_options); - } - commands::ProverEntity::CompileAndProve(args) => { - let out_file_path = args.program_path.replace(".cairo", ".json"); - match try_compile(&args.program_path, &out_file_path) { - Ok(_) => { - let Some((proof, pub_inputs)) = generate_proof(&out_file_path, &proof_options) - else { - return; - }; - - write_proof(proof, pub_inputs, args.proof_path); - } - Err(err) => { - eprintln!("{}", err) - } - } - } - commands::ProverEntity::CompileProveAndVerify(args) => { - let out_file_path = args.program_path.replace(".cairo", ".json"); - match try_compile(&args.program_path, &out_file_path) { - Ok(_) => { - let Some((proof, pub_inputs)) = generate_proof(&out_file_path, &proof_options) - else { - return; - }; - verify_proof(proof, pub_inputs, &proof_options); - } - Err(err) => { - eprintln!("{}", err) - } - } - } - } -} diff --git a/provers/cairo/src/register_states.rs b/provers/cairo/src/register_states.rs deleted file mode 100644 index a63afcbdf..000000000 --- a/provers/cairo/src/register_states.rs +++ /dev/null @@ -1,259 +0,0 @@ -use super::{ - cairo_mem::CairoMemory, - decode::{instruction_flags::CairoInstructionFlags, instruction_offsets::InstructionOffsets}, - errors::{CairoImportError, InstructionDecodingError}, -}; -use std::fs; - -#[derive(PartialEq, Clone, Debug)] -pub struct RegistersState { - pub pc: u64, - pub fp: u64, - pub ap: u64, -} - -impl RegistersState { - fn instruction_flags_and_offsets( - &self, - memory: &CairoMemory, - ) -> Result<(CairoInstructionFlags, InstructionOffsets), InstructionDecodingError> { - let instruction = memory - .get(&self.pc) - .ok_or(InstructionDecodingError::InstructionNotFound)?; - - let flags = CairoInstructionFlags::try_from(instruction)?; - let offsets = InstructionOffsets::new(instruction); - - Ok((flags, offsets)) - } -} - -#[derive(PartialEq, Clone, Debug)] -pub struct RegisterStates { - pub rows: Vec, -} - -impl RegisterStates { - pub fn steps(&self) -> usize { - self.rows.len() - } - - pub fn flags_and_offsets( - &self, - memory: &CairoMemory, - ) -> Result, InstructionDecodingError> { - self.rows - .iter() - .map(|state| state.instruction_flags_and_offsets(memory)) - .collect() - } - - pub fn from_bytes_le(bytes: &[u8]) -> Result { - // Each row of the trace is a RegisterState - // ap, fp, pc, each 8 bytes long (u64) - const ROW_SIZE: usize = 8 * 3; - - if bytes.len() % ROW_SIZE != 0 { - return Err(CairoImportError::IncorrectNumberOfBytes); - } - let num_rows = bytes.len() / ROW_SIZE; - - let rows = (0..num_rows) - .map(|i| RegistersState { - ap: u64::from_le_bytes(bytes[i * ROW_SIZE..i * ROW_SIZE + 8].try_into().unwrap()), - fp: u64::from_le_bytes( - bytes[i * ROW_SIZE + 8..i * ROW_SIZE + 16] - .try_into() - .unwrap(), - ), - pc: u64::from_le_bytes( - bytes[i * ROW_SIZE + 16..i * 24 + ROW_SIZE] - .try_into() - .unwrap(), - ), - }) - .collect::>(); - - Ok(Self { rows }) - } - - pub fn from_file(path: &str) -> Result { - let data = fs::read(path)?; - Self::from_bytes_le(&data) - } -} - -#[cfg(test)] -mod tests { - - use crate::{ - decode::instruction_flags::{ - ApUpdate, CairoOpcode, DstReg, Op0Reg, Op1Src, PcUpdate, ResLogic, - }, - Felt252, - }; - - use super::*; - use std::collections::HashMap; - - #[test] - fn mul_program_gives_expected_trace() { - /* - Hex from the trace of the following cairo program - - func main() { - let x = 2; - let y = 3; - assert x * y = 6; - return(); - } - - Generated with: - - cairo-compile multiply.cairo --output multiply.out - - cairo-run --layout all --trace_file trace.out --memory_file mem.out --program multiply.out - - xxd -p trace.out - */ - - let bytes = hex::decode("080000000000000008000000000000000100000000000000090000000000000008000000000000000300000000000000090000000000000008000000000000000500000000000000").unwrap(); - - let register_states = RegisterStates::from_bytes_le(&bytes); - - let expected_state0 = RegistersState { - ap: 8, - fp: 8, - pc: 1, - }; - - let expected_state1 = RegistersState { - ap: 9, - fp: 8, - pc: 3, - }; - - let expected_state2 = RegistersState { - ap: 9, - fp: 8, - pc: 5, - }; - - let expected_reg_states = RegisterStates { - rows: [expected_state0, expected_state1, expected_state2].to_vec(), - }; - - assert_eq!(register_states.unwrap(), expected_reg_states) - } - - #[test] - fn wrong_amount_of_bytes_gives_err() { - let bytes = hex::decode("080000000000").unwrap(); - - match RegisterStates::from_bytes_le(&bytes) { - Err(CairoImportError::IncorrectNumberOfBytes) => (), - Err(_) => panic!(), - Ok(_) => panic!(), - } - } - - #[test] - fn loads_mul_trace_from_file_correctly() { - let base_dir = env!("CARGO_MANIFEST_DIR"); - - dbg!(base_dir); - let dir = base_dir.to_owned() + "/src/tests/data/mul_trace.out"; - - let register_states = RegisterStates::from_file(&dir).unwrap(); - - let expected_state0 = RegistersState { - ap: 8, - fp: 8, - pc: 1, - }; - - let expected_state1 = RegistersState { - ap: 9, - fp: 8, - pc: 3, - }; - - let expected_state2 = RegistersState { - ap: 9, - fp: 8, - pc: 5, - }; - - let expected_reg_states = RegisterStates { - rows: [expected_state0, expected_state1, expected_state2].to_vec(), - }; - - assert_eq!(register_states, expected_reg_states); - } - - #[test] - fn decode_instruction_flags_and_offsets() { - let data = HashMap::from([ - (1u64, Felt252::from(0x480680017fff8000)), - (2u64, Felt252::from(0x1104800180018000)), - ]); - - let memory = CairoMemory::new(data); - let state1 = RegistersState { - ap: 8, - fp: 8, - pc: 1, - }; - let state2 = RegistersState { - ap: 9, - fp: 8, - pc: 2, - }; - - let trace = RegisterStates { - rows: [state1, state2].to_vec(), - }; - - let expected_flags1 = CairoInstructionFlags { - opcode: CairoOpcode::AssertEq, - pc_update: PcUpdate::Regular, - ap_update: ApUpdate::Add1, - op0_reg: Op0Reg::FP, - op1_src: Op1Src::Imm, - res_logic: ResLogic::Op1, - dst_reg: DstReg::AP, - }; - - let expected_offsets1 = InstructionOffsets { - off_dst: 0, - off_op0: -1, - off_op1: 1, - }; - - let expected_flags2 = CairoInstructionFlags { - opcode: CairoOpcode::Call, - pc_update: PcUpdate::JumpRel, - ap_update: ApUpdate::Regular, - op0_reg: Op0Reg::AP, - op1_src: Op1Src::Imm, - res_logic: ResLogic::Op1, - dst_reg: DstReg::AP, - }; - - let expected_offsets2 = InstructionOffsets { - off_dst: 0, - off_op0: 1, - off_op1: 1, - }; - - let flags_and_offsets = trace.flags_and_offsets(&memory).unwrap(); - - assert_eq!( - flags_and_offsets, - vec![ - (expected_flags1, expected_offsets1), - (expected_flags2, expected_offsets2) - ] - ); - } -} diff --git a/provers/cairo/src/runner/file_writer.rs b/provers/cairo/src/runner/file_writer.rs deleted file mode 100644 index a116c66cc..000000000 --- a/provers/cairo/src/runner/file_writer.rs +++ /dev/null @@ -1,35 +0,0 @@ -use bincode::enc::write::Writer; -use std::io::{self, Write}; - -pub struct FileWriter { - buf_writer: io::BufWriter, - bytes_written: usize, -} - -impl Writer for FileWriter { - fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { - self.buf_writer - .write_all(bytes) - .map_err(|e| bincode::error::EncodeError::Io { - inner: e, - index: self.bytes_written, - })?; - - self.bytes_written += bytes.len(); - - Ok(()) - } -} - -impl FileWriter { - pub fn new(buf_writer: io::BufWriter) -> Self { - Self { - buf_writer, - bytes_written: 0, - } - } - - pub fn flush(&mut self) -> io::Result<()> { - self.buf_writer.flush() - } -} diff --git a/provers/cairo/src/runner/mod.rs b/provers/cairo/src/runner/mod.rs deleted file mode 100644 index cb9e2c994..000000000 --- a/provers/cairo/src/runner/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod file_writer; -pub mod run; -pub mod vec_writer; diff --git a/provers/cairo/src/runner/run.rs b/provers/cairo/src/runner/run.rs deleted file mode 100644 index b46770630..000000000 --- a/provers/cairo/src/runner/run.rs +++ /dev/null @@ -1,187 +0,0 @@ -use crate::air::{PublicInputs, Segment, SegmentName}; -use crate::cairo_layout::CairoLayout; -use crate::cairo_mem::CairoMemory; -use crate::execution_trace::build_main_trace; -use crate::register_states::RegisterStates; -use crate::Felt252; - -use super::vec_writer::VecWriter; -use cairo_vm::cairo_run::{self, EncodeTraceError}; - -use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor; - -use cairo_vm::vm::errors::{ - cairo_run_errors::CairoRunError, trace_errors::TraceError, vm_errors::VirtualMachineError, -}; - -use cairo_vm::without_std::collections::HashMap; -use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; -use stark_platinum_prover::trace::TraceTable; - -#[derive(Debug)] -pub enum Error { - IO(std::io::Error), - Runner(CairoRunError), - EncodeTrace(EncodeTraceError), - VirtualMachine(VirtualMachineError), - Trace(TraceError), -} - -impl From for Error { - fn from(err: std::io::Error) -> Error { - Error::IO(err) - } -} - -impl From for Error { - fn from(err: CairoRunError) -> Error { - Error::Runner(err) - } -} - -impl From for Error { - fn from(err: EncodeTraceError) -> Error { - Error::EncodeTrace(err) - } -} - -impl From for Error { - fn from(err: VirtualMachineError) -> Error { - Error::VirtualMachine(err) - } -} - -impl From for Error { - fn from(err: TraceError) -> Error { - Error::Trace(err) - } -} - -/// Runs a cairo program in JSON format and returns trace, memory and program length. -/// Uses [cairo-rs](https://github.com/lambdaclass/cairo-rs/) project to run the program. -/// -/// # Params -/// -/// `entrypoint_function` - the name of the entrypoint function tu run. If `None` is provided, the default value is `main`. -/// `layout` - type of layout of Cairo. -/// `program_content` - content of the input file. -/// `trace_path` - path where to store the generated trace file. -/// `memory_path` - path where to store the generated memory file. -/// -/// # Returns -/// -/// Ok() in case of succes, with the following values: -/// - register_states -/// - cairo_mem -/// - data_len -/// - range_check: an Option<(usize, usize)> containing the start and end of range check. -/// `Error` indicating the type of error. -#[allow(clippy::type_complexity)] -pub fn run_program( - entrypoint_function: Option<&str>, - layout: CairoLayout, - program_content: &[u8], -) -> Result<(RegisterStates, CairoMemory, PublicInputs), Error> { - // default value for entrypoint is "main" - let entrypoint = entrypoint_function.unwrap_or("main"); - - let trace_enabled = true; - let mut hint_executor = BuiltinHintProcessor::new_empty(); - let cairo_run_config = cairo_run::CairoRunConfig { - entrypoint, - trace_enabled, - relocate_mem: true, - layout: layout.as_str(), - proof_mode: true, - secure_run: None, - disable_trace_padding: false, - }; - - let (runner, vm) = - match cairo_run::cairo_run(program_content, &cairo_run_config, &mut hint_executor) { - Ok(runner) => runner, - Err(error) => { - eprintln!("{error}"); - panic!(); - } - }; - - let relocated_trace = vm.get_relocated_trace().unwrap(); - - let mut trace_vec = Vec::::new(); - let mut trace_writer = VecWriter::new(&mut trace_vec); - trace_writer.write_encoded_trace(relocated_trace); - - let relocated_memory = &runner.relocated_memory; - - let mut memory_vec = Vec::::new(); - let mut memory_writer = VecWriter::new(&mut memory_vec); - memory_writer.write_encoded_memory(relocated_memory); - - trace_writer.flush().unwrap(); - memory_writer.flush().unwrap(); - - //TO DO: Better error handling - let cairo_mem = CairoMemory::from_bytes_le(&memory_vec).unwrap(); - let register_states = RegisterStates::from_bytes_le(&trace_vec).unwrap(); - - let vm_pub_inputs = runner.get_air_public_input(&vm).unwrap(); - - let mut pub_memory: HashMap = HashMap::new(); - vm_pub_inputs.public_memory.iter().for_each(|mem_cell| { - let addr = Felt252::from(mem_cell.address as u64); - let value = Felt252::from_hex_unchecked(&mem_cell.value.as_ref().unwrap().to_str_radix(16)); - pub_memory.insert(addr, value); - }); - - let mut memory_segments: HashMap = HashMap::new(); - vm_pub_inputs.memory_segments.iter().for_each(|(k, v)| { - memory_segments.insert(SegmentName::from(*k), Segment::from(v)); - }); - - let num_steps = register_states.steps(); - let public_inputs = PublicInputs { - pc_init: Felt252::from(register_states.rows[0].pc), - ap_init: Felt252::from(register_states.rows[0].ap), - fp_init: Felt252::from(register_states.rows[0].fp), - pc_final: Felt252::from(register_states.rows[num_steps - 1].pc), - ap_final: Felt252::from(register_states.rows[num_steps - 1].ap), - range_check_min: Some(vm_pub_inputs.rc_min as u16), - range_check_max: Some(vm_pub_inputs.rc_max as u16), - memory_segments, - public_memory: pub_memory, - num_steps, - }; - - Ok((register_states, cairo_mem, public_inputs)) -} - -pub fn generate_prover_args( - program_content: &[u8], - layout: CairoLayout, -) -> Result<(TraceTable, PublicInputs), Error> { - let (register_states, memory, mut public_inputs) = run_program(None, layout, program_content)?; - - let main_trace = build_main_trace(®ister_states, &memory, &mut public_inputs); - - Ok((main_trace, public_inputs)) -} - -pub fn generate_prover_args_from_trace( - trace_bin_path: &str, - memory_bin_path: &str, -) -> Result<(TraceTable, PublicInputs), Error> { - // ## Generating the prover args - let register_states = - RegisterStates::from_file(trace_bin_path).expect("Cairo trace bin file not found"); - let memory = - CairoMemory::from_file(memory_bin_path).expect("Cairo memory binary file not found"); - - // data length - let data_len = 0_usize; - let mut pub_inputs = PublicInputs::from_regs_and_mem(®ister_states, &memory, data_len); - - let main_trace = build_main_trace(®ister_states, &memory, &mut pub_inputs); - - Ok((main_trace, pub_inputs)) -} diff --git a/provers/cairo/src/runner/vec_writer.rs b/provers/cairo/src/runner/vec_writer.rs deleted file mode 100644 index 7e8cb52d0..000000000 --- a/provers/cairo/src/runner/vec_writer.rs +++ /dev/null @@ -1,58 +0,0 @@ -use cairo_vm::felt::Felt252; -use std::io::{self, Write}; - -pub struct VecWriter<'a> { - buf_writer: &'a mut Vec, -} - -impl bincode::enc::write::Writer for VecWriter<'_> { - fn write(&mut self, bytes: &[u8]) -> Result<(), bincode::error::EncodeError> { - self.buf_writer - .write_all(bytes) - .expect("Shouldn't fail in memory vector"); - - Ok(()) - } -} - -impl<'a> VecWriter<'a> { - pub fn new(vec: &'a mut Vec) -> Self { - Self { buf_writer: vec } - } - - pub fn flush(&mut self) -> io::Result<()> { - self.buf_writer.flush() - } - - pub fn write_encoded_trace( - &mut self, - relocated_trace: &[cairo_vm::vm::trace::trace_entry::TraceEntry], - ) { - for entry in relocated_trace.iter() { - self.buf_writer - .extend_from_slice(&((entry.ap as u64).to_le_bytes())); - self.buf_writer - .extend_from_slice(&((entry.fp as u64).to_le_bytes())); - self.buf_writer - .extend_from_slice(&((entry.pc as u64).to_le_bytes())); - } - } - - /// Writes a binary representation of the relocated memory. - /// - /// The memory pairs (address, value) are encoded and concatenated: - /// * address -> 8-byte encoded - /// * value -> 32-byte encoded - pub fn write_encoded_memory(&mut self, relocated_memory: &[Option]) { - for (i, memory_cell) in relocated_memory.iter().enumerate() { - match memory_cell { - None => continue, - Some(unwrapped_memory_cell) => { - self.buf_writer.extend_from_slice(&(i as u64).to_le_bytes()); - self.buf_writer - .extend_from_slice(&unwrapped_memory_cell.to_le_bytes()); - } - } - } - } -} diff --git a/provers/cairo/src/tests/data/mul_mem.out b/provers/cairo/src/tests/data/mul_mem.out deleted file mode 100644 index f4f866c2d..000000000 Binary files a/provers/cairo/src/tests/data/mul_mem.out and /dev/null differ diff --git a/provers/cairo/src/tests/data/mul_trace.out b/provers/cairo/src/tests/data/mul_trace.out deleted file mode 100644 index a4a295fdb..000000000 Binary files a/provers/cairo/src/tests/data/mul_trace.out and /dev/null differ diff --git a/provers/cairo/src/tests/integration_tests.rs b/provers/cairo/src/tests/integration_tests.rs deleted file mode 100644 index 79f051830..000000000 --- a/provers/cairo/src/tests/integration_tests.rs +++ /dev/null @@ -1,194 +0,0 @@ -use crate::{ - air::{generate_cairo_proof, verify_cairo_proof, CairoAIR}, - cairo_layout::CairoLayout, - runner::run::generate_prover_args, - tests::utils::{ - cairo0_program_path, test_prove_cairo_program, test_prove_cairo_program_from_trace, - }, - Felt252, -}; -use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; -use stark_platinum_prover::{ - debug::validate_trace, - domain::Domain, - proof::{ - options::{ProofOptions, SecurityLevel}, - stark::StarkProof, - }, - traits::AIR, - transcript::StoneProverTranscript, -}; - -#[test_log::test] -fn test_prove_cairo_simple_program() { - let layout = CairoLayout::Plain; - test_prove_cairo_program(&cairo0_program_path("simple_program.json"), layout); -} - -#[test_log::test] -fn test_prove_cairo_fibonacci_5() { - let layout = CairoLayout::Plain; - test_prove_cairo_program(&cairo0_program_path("fibonacci_5.json"), layout); -} - -#[test_log::test] -fn test_prove_cairo_fibonacci_5_from_trace() { - test_prove_cairo_program_from_trace( - &cairo0_program_path("fibonacci_5_trace.bin"), - &cairo0_program_path("fibonacci_5_memory.bin"), - ); -} - -#[test_log::test] -fn test_verifier_rejects_wrong_authentication_paths() { - // Setup - let proof_options = ProofOptions::default_test_options(); - let program_content = std::fs::read(cairo0_program_path("fibonacci_5.json")).unwrap(); - let (main_trace, pub_inputs) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - // Generate the proof - let mut proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - - // Change order of authentication path hashes - let query = 0; - let mut original_path = proof.deep_poly_openings[query] - .main_trace_polys - .proof - .merkle_path - .clone(); - original_path.swap(0, 1); - // For the test to make sense, we have to make sure - // that the two hashes are different. - assert_ne!(original_path[0], original_path[1]); - proof.deep_poly_openings[query] - .main_trace_polys - .proof - .merkle_path = original_path; - - // Verifier should reject the proof - assert!(!verify_cairo_proof(&proof, &pub_inputs, &proof_options)); -} - -#[test_log::test] -fn test_prove_cairo_fibonacci_1000() { - let layout = CairoLayout::Plain; - test_prove_cairo_program(&cairo0_program_path("fibonacci_1000.json"), layout); -} - -// #[cfg_attr(feature = "metal", ignore)] -// #[test_log::test] -// fn test_prove_cairo_fibonacci_casm() { -// let layout = CairoLayout::Plain; -// test_prove_cairo1_program(&cairo1_program_path("fibonacci_cairo1_mod.casm"), layout); -// } - -#[test_log::test] -fn test_verifier_rejects_proof_of_a_slightly_different_program() { - let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap(); - let (main_trace, mut pub_input) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - let proof_options = ProofOptions::default_test_options(); - - let proof = generate_cairo_proof(&main_trace, &pub_input, &proof_options).unwrap(); - - // We modify the original program and verify using this new "corrupted" version - let mut corrupted_program = pub_input.public_memory.clone(); - corrupted_program.insert(Felt252::one(), Felt252::from(5)); - corrupted_program.insert(Felt252::from(3), Felt252::from(5)); - - // Here we use the corrupted version of the program in the public inputs - pub_input.public_memory = corrupted_program; - assert!(!verify_cairo_proof(&proof, &pub_input, &proof_options)); -} - -#[test_log::test] -fn test_verifier_rejects_proof_with_different_range_bounds() { - let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap(); - let (main_trace, mut pub_inputs) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - let proof_options = ProofOptions::default_test_options(); - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - - pub_inputs.range_check_min = Some(pub_inputs.range_check_min.unwrap() + 1); - assert!(!verify_cairo_proof(&proof, &pub_inputs, &proof_options)); - - pub_inputs.range_check_min = Some(pub_inputs.range_check_min.unwrap() - 1); - pub_inputs.range_check_max = Some(pub_inputs.range_check_max.unwrap() - 1); - assert!(!verify_cairo_proof(&proof, &pub_inputs, &proof_options)); -} - -#[test_log::test] -fn test_verifier_rejects_proof_with_different_security_params() { - let program_content = std::fs::read(cairo0_program_path("fibonacci_5.json")).unwrap(); - let (main_trace, pub_inputs) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - let proof_options_prover = ProofOptions::new_secure(SecurityLevel::Conjecturable80Bits, 3); - - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options_prover).unwrap(); - - let proof_options_verifier = ProofOptions::new_secure(SecurityLevel::Conjecturable128Bits, 3); - - assert!(!verify_cairo_proof( - &proof, - &pub_inputs, - &proof_options_verifier - )); -} - -#[test] -fn check_simple_cairo_trace_evaluates_to_zero() { - let program_content = std::fs::read(cairo0_program_path("simple_program.json")).unwrap(); - let (main_trace, public_input) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - let mut trace_polys = main_trace.compute_trace_polys::(); - let mut transcript = StoneProverTranscript::new(&[]); - - let proof_options = ProofOptions::default_test_options(); - let cairo_air = CairoAIR::new(main_trace.n_rows(), &public_input, &proof_options); - let rap_challenges = cairo_air.build_rap_challenges(&mut transcript); - - let aux_trace = cairo_air.build_auxiliary_trace(&main_trace, &rap_challenges); - let aux_polys = aux_trace.compute_trace_polys::(); - - trace_polys.extend_from_slice(&aux_polys); - - let domain = Domain::new(&cairo_air); - - assert!(validate_trace( - &cairo_air, - &trace_polys, - &aux_polys, - &domain, - &rap_challenges - )); -} - -#[test] -fn deserialize_and_verify() { - let program_content = std::fs::read(cairo0_program_path("fibonacci_10.json")).unwrap(); - let (main_trace, pub_inputs) = - generate_prover_args(&program_content, CairoLayout::Plain).unwrap(); - - let proof_options = ProofOptions::default_test_options(); - - // The proof is generated and serialized. - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - let proof_bytes: Vec = serde_cbor::to_vec(&proof).unwrap(); - - // The trace and original proof are dropped to show that they are decoupled from - // the verifying process. - drop(main_trace); - drop(proof); - - // At this point, the verifier only knows about the serialized proof, the proof options - // and the public inputs. - let proof: StarkProof = - serde_cbor::from_slice(&proof_bytes).unwrap(); - - // The proof is verified successfully. - assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options)); -} diff --git a/provers/cairo/src/tests/mod.rs b/provers/cairo/src/tests/mod.rs deleted file mode 100644 index 8ffce3ed0..000000000 --- a/provers/cairo/src/tests/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod integration_tests; -pub mod utils; diff --git a/provers/cairo/src/tests/utils.rs b/provers/cairo/src/tests/utils.rs deleted file mode 100644 index 671d74f94..000000000 --- a/provers/cairo/src/tests/utils.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::{ - air::{generate_cairo_proof, verify_cairo_proof}, - cairo_layout::CairoLayout, - runner::run::generate_prover_args, - runner::run::generate_prover_args_from_trace, -}; -use stark_platinum_prover::proof::options::ProofOptions; -use std::time::Instant; - -pub fn cairo0_program_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const CAIRO0_BASE_REL_PATH: &str = "/cairo_programs/cairo0/"; - let program_base_path = CARGO_DIR.to_string() + CAIRO0_BASE_REL_PATH; - program_base_path + program_name -} - -pub fn cairo1_program_path(program_name: &str) -> String { - const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); - const CAIRO1_BASE_REL_PATH: &str = "/cairo_programs/cairo1/"; - let program_base_path = CARGO_DIR.to_string() + CAIRO1_BASE_REL_PATH; - program_base_path + program_name -} - -/// Loads the program in path, runs it with the Cairo VM, and makes a proof of it -pub fn test_prove_cairo_program(file_path: &str, layout: CairoLayout) { - let proof_options = ProofOptions::default_test_options(); - let timer = Instant::now(); - println!("Making proof ..."); - - let program_content = std::fs::read(file_path).unwrap(); - let (main_trace, pub_inputs) = generate_prover_args(&program_content, layout).unwrap(); - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - println!(" Time spent in proving: {:?} \n", timer.elapsed()); - - assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options)); -} - -pub fn test_prove_cairo_program_from_trace(trace_bin_path: &str, memory_bin_path: &str) { - let proof_options = ProofOptions::default_test_options(); - let (main_trace, pub_inputs) = - generate_prover_args_from_trace(trace_bin_path, memory_bin_path).unwrap(); - - // println - let timer = Instant::now(); - println!("Making proof ..."); - let proof = generate_cairo_proof(&main_trace, &pub_inputs, &proof_options).unwrap(); - println!(" Time spent in proving: {:?} \n", timer.elapsed()); - assert!(verify_cairo_proof(&proof, &pub_inputs, &proof_options)); -} diff --git a/provers/cairo/src/transition_constraints.rs b/provers/cairo/src/transition_constraints.rs deleted file mode 100644 index c5a761622..000000000 --- a/provers/cairo/src/transition_constraints.rs +++ /dev/null @@ -1,3219 +0,0 @@ -use crate::Felt252; -use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; -use stark_platinum_prover::{ - constraints::transition::TransitionConstraint, frame::Frame, table::TableView, -}; - -#[derive(Clone)] -pub struct BitPrefixFlag0; -impl BitPrefixFlag0 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag0 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 0 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag1; -impl BitPrefixFlag1 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag1 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 1 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag2; -impl BitPrefixFlag2 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag2 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 2 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag3; -impl BitPrefixFlag3 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag3 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 3 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag4; -impl BitPrefixFlag4 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag4 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag4 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 4 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag5; -impl BitPrefixFlag5 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag5 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag5 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 5 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag6; -impl BitPrefixFlag6 { - pub fn new() -> Self { - Self - } -} -impl Default for BitPrefixFlag6 { - fn default() -> Self { - Self::new() - } -} - -impl TransitionConstraint for BitPrefixFlag6 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 6 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag7; -impl Default for BitPrefixFlag7 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag7 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag7 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 7 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag8; -impl Default for BitPrefixFlag8 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag8 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag8 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 8 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag9; -impl Default for BitPrefixFlag9 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag9 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag9 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 9 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -#[derive(Clone)] -pub struct BitPrefixFlag10; -impl Default for BitPrefixFlag10 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag10 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag10 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 10 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct BitPrefixFlag11; -impl Default for BitPrefixFlag11 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag11 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag11 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 11 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct BitPrefixFlag12; -impl Default for BitPrefixFlag12 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag12 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag12 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 12 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct BitPrefixFlag13; -impl Default for BitPrefixFlag13 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag13 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag13 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 13 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct BitPrefixFlag14; -impl Default for BitPrefixFlag14 { - fn default() -> Self { - Self::new() - } -} - -impl BitPrefixFlag14 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for BitPrefixFlag14 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 14 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let constraint_idx = self.constraint_idx(); - - let current_flag = current_step.get_main_evaluation_element(0, constraint_idx); - let next_flag = current_step.get_main_evaluation_element(0, constraint_idx + 1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let bit = current_flag - two * next_flag; - - let res = bit * (bit - one); - - transition_evaluations[constraint_idx] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct ZeroFlagConstraint; -impl Default for ZeroFlagConstraint { - fn default() -> Self { - Self::new() - } -} - -impl ZeroFlagConstraint { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for ZeroFlagConstraint { - fn degree(&self) -> usize { - 1 - } - - fn constraint_idx(&self) -> usize { - 15 - } - - fn evaluate( - &self, - frame: &stark_platinum_prover::frame::Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let zero_flag = current_step.get_main_evaluation_element(0, 15); - - transition_evaluations[self.constraint_idx()] = *zero_flag; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct FlagOp1BaseOp0BitConstraint; -impl Default for FlagOp1BaseOp0BitConstraint { - fn default() -> Self { - Self::new() - } -} - -impl FlagOp1BaseOp0BitConstraint { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for FlagOp1BaseOp0BitConstraint { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 54 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_op1_imm = current_step.get_main_evaluation_element(0, 2) - - two * current_step.get_main_evaluation_element(0, 3); - let f_op1_fp = current_step.get_main_evaluation_element(0, 3) - - two * current_step.get_main_evaluation_element(0, 4); - let f_op1_ap = current_step.get_main_evaluation_element(0, 4) - - two * current_step.get_main_evaluation_element(0, 5); - - let f_op1_base_op0_bit = one - f_op1_imm - f_op1_fp - f_op1_ap; - - let res = f_op1_base_op0_bit * (f_op1_base_op0_bit - one); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct FlagResOp1BitConstraint; -impl Default for FlagResOp1BitConstraint { - fn default() -> Self { - Self::new() - } -} - -impl FlagResOp1BitConstraint { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for FlagResOp1BitConstraint { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 55 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_res_add = current_step.get_main_evaluation_element(0, 5) - - two * current_step.get_main_evaluation_element(0, 6); - let f_res_mul = current_step.get_main_evaluation_element(0, 6) - - two * current_step.get_main_evaluation_element(0, 7); - let f_pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - - let f_res_op1_bit = one - f_res_add - f_res_mul - f_pc_jnz; - - let res = f_res_op1_bit * (f_res_op1_bit - one); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct FlagPcUpdateRegularBit; -impl Default for FlagPcUpdateRegularBit { - fn default() -> Self { - Self::new() - } -} - -impl FlagPcUpdateRegularBit { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for FlagPcUpdateRegularBit { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 56 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_jump_abs = current_step.get_main_evaluation_element(0, 7) - - two * current_step.get_main_evaluation_element(0, 8); - let f_jump_rel = current_step.get_main_evaluation_element(0, 8) - - two * current_step.get_main_evaluation_element(0, 9); - let f_pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - - let flag_pc_update_regular_bit = one - f_jump_abs - f_jump_rel - f_pc_jnz; - - let res = flag_pc_update_regular_bit * (flag_pc_update_regular_bit - one); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct FlagFpUpdateRegularBit; -impl Default for FlagFpUpdateRegularBit { - fn default() -> Self { - Self::new() - } -} - -impl FlagFpUpdateRegularBit { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for FlagFpUpdateRegularBit { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 57 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_opcode_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - let f_opcode_ret = current_step.get_main_evaluation_element(0, 13) - - two * current_step.get_main_evaluation_element(0, 14); - - let flag_fp_update_regular_bit = one - f_opcode_call - f_opcode_ret; - - let res = flag_fp_update_regular_bit * (flag_fp_update_regular_bit - one); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct InstructionUnpacking; -impl Default for InstructionUnpacking { - fn default() -> Self { - Self::new() - } -} - -impl InstructionUnpacking { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for InstructionUnpacking { - fn degree(&self) -> usize { - 1 - } - - fn constraint_idx(&self) -> usize { - 16 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - let b16 = two.pow(16u32); - let b32 = two.pow(32u32); - let b48 = two.pow(48u32); - - // Named like this to match the Cairo whitepaper's notation. - let f0_squiggle = current_step.get_main_evaluation_element(0, 0); - - let instruction = current_step.get_main_evaluation_element(0, 23); - let off_dst = current_step.get_main_evaluation_element(0, 27); - let off_op0 = current_step.get_main_evaluation_element(0, 28); - let off_op1 = current_step.get_main_evaluation_element(0, 29); - - let res = off_dst + b16 * off_op0 + b32 * off_op1 + b48 * f0_squiggle - instruction; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesCallOff0; -impl Default for CpuOpcodesCallOff0 { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesCallOff0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesCallOff0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 58 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let two = Felt252::from(2); - let b15 = two.pow(15u32); - - let f_opcode_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - - let off_dst = current_step.get_main_evaluation_element(0, 27); - - let res = f_opcode_call * (off_dst - b15); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesCallOff1; -impl Default for CpuOpcodesCallOff1 { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesCallOff1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesCallOff1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 59 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - let b15 = two.pow(15u32); - - let f_opcode_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - let off_op0 = current_step.get_main_evaluation_element(0, 28); - - let res = f_opcode_call * (off_op0 - b15 - one); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesCallFlags; -impl Default for CpuOpcodesCallFlags { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesCallFlags { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesCallFlags { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 60 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_opcode_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - - let bit_flag0 = current_step.get_main_evaluation_element(0, 0) - - two * current_step.get_main_evaluation_element(0, 1); - let bit_flag1 = current_step.get_main_evaluation_element(0, 1) - - two * current_step.get_main_evaluation_element(0, 2); - - let res = - f_opcode_call * (two * f_opcode_call + one + one - bit_flag0 - bit_flag1 - two - two); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesRetOff0; -impl Default for CpuOpcodesRetOff0 { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesRetOff0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesRetOff0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 61 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - let b15 = two.pow(15u32); - - let f_opcode_ret = current_step.get_main_evaluation_element(0, 13) - - two * current_step.get_main_evaluation_element(0, 14); - let off_dst = current_step.get_main_evaluation_element(0, 27); - - let res = f_opcode_ret * (off_dst + two - b15); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesRetOff2; -impl Default for CpuOpcodesRetOff2 { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesRetOff2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesRetOff2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 62 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - let b15 = two.pow(15u32); - - let f_opcode_ret = current_step.get_main_evaluation_element(0, 13) - - two * current_step.get_main_evaluation_element(0, 14); - let off_op1 = current_step.get_main_evaluation_element(0, 29); - - let res = f_opcode_ret * (off_op1 + one - b15); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesRetFlags; -impl Default for CpuOpcodesRetFlags { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesRetFlags { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesRetFlags { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 63 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let f_opcode_ret = current_step.get_main_evaluation_element(0, 13) - - two * current_step.get_main_evaluation_element(0, 14); - let flag0 = current_step.get_main_evaluation_element(0, 0) - - two * current_step.get_main_evaluation_element(0, 1); - let flag3 = current_step.get_main_evaluation_element(0, 3) - - two * current_step.get_main_evaluation_element(0, 4); - let flag7 = current_step.get_main_evaluation_element(0, 7) - - two * current_step.get_main_evaluation_element(0, 8); - - let f_res_add = current_step.get_main_evaluation_element(0, 5) - - two * current_step.get_main_evaluation_element(0, 6); - let f_res_mul = current_step.get_main_evaluation_element(0, 6) - - two * current_step.get_main_evaluation_element(0, 7); - let f_pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - - let f_res_op1_bit = one - f_res_add - f_res_mul - f_pc_jnz; - - let res = f_opcode_ret * (flag7 + flag0 + flag3 + f_res_op1_bit - two - two); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOperandsMemDstAddr; -impl Default for CpuOperandsMemDstAddr { - fn default() -> Self { - Self::new() - } -} - -impl CpuOperandsMemDstAddr { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOperandsMemDstAddr { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 17 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - let one = Felt252::one(); - let b15 = two.pow(15u32); - let dst_fp = current_step.get_main_evaluation_element(0, 0) - - two * current_step.get_main_evaluation_element(0, 1); - let ap = current_step.get_main_evaluation_element(0, 17); - let fp = current_step.get_main_evaluation_element(0, 18); - let off_dst = current_step.get_main_evaluation_element(0, 27); - let dst_addr = current_step.get_main_evaluation_element(0, 20); - - let res = dst_fp * fp + (one - dst_fp) * ap + (off_dst - b15) - dst_addr; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOperandsMem0Addr; -impl Default for CpuOperandsMem0Addr { - fn default() -> Self { - Self::new() - } -} - -impl CpuOperandsMem0Addr { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOperandsMem0Addr { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 18 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - let one = Felt252::one(); - let b15 = two.pow(15u32); - - let op0_fp = current_step.get_main_evaluation_element(0, 1) - - two * current_step.get_main_evaluation_element(0, 2); - - let ap = current_step.get_main_evaluation_element(0, 17); - let fp = current_step.get_main_evaluation_element(0, 18); - - let off_op0 = current_step.get_main_evaluation_element(0, 28); - let op0_addr = current_step.get_main_evaluation_element(0, 21); - - let res = op0_fp * fp + (one - op0_fp) * ap + (off_op0 - b15) - op0_addr; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOperandsMem1Addr; -impl Default for CpuOperandsMem1Addr { - fn default() -> Self { - Self::new() - } -} - -impl CpuOperandsMem1Addr { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOperandsMem1Addr { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 19 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - let two = Felt252::from(2); - let b15 = two.pow(15u32); - - let op1_val = current_step.get_main_evaluation_element(0, 2) - - two * current_step.get_main_evaluation_element(0, 3); - let op1_fp = current_step.get_main_evaluation_element(0, 3) - - two * current_step.get_main_evaluation_element(0, 4); - let op1_ap = current_step.get_main_evaluation_element(0, 4) - - two * current_step.get_main_evaluation_element(0, 5); - - let op0 = current_step.get_main_evaluation_element(0, 25); - let off_op1 = current_step.get_main_evaluation_element(0, 29); - let op1_addr = current_step.get_main_evaluation_element(0, 22); - - let ap = current_step.get_main_evaluation_element(0, 17); - let fp = current_step.get_main_evaluation_element(0, 18); - let pc = current_step.get_main_evaluation_element(0, 19); - - let res = op1_val * pc - + op1_ap * ap - + op1_fp * fp - + (one - op1_val - op1_ap - op1_fp) * op0 - + (off_op1 - b15) - - op1_addr; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -// cpu/update_registers/update_ap/ap_update -pub struct CpuUpdateRegistersApUpdate; -impl Default for CpuUpdateRegistersApUpdate { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersApUpdate { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuUpdateRegistersApUpdate { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 20 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let two = Felt252::from(2); - - let ap = current_step.get_main_evaluation_element(0, 17); - let next_ap = next_step.get_main_evaluation_element(0, 17); - let res = current_step.get_main_evaluation_element(0, 16); - - let ap_one = current_step.get_main_evaluation_element(0, 11) - - two * current_step.get_main_evaluation_element(0, 12); - let opc_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - let ap_add = current_step.get_main_evaluation_element(0, 10) - - two * current_step.get_main_evaluation_element(0, 11); - - let res = ap + ap_add * res + ap_one + opc_call * two - next_ap; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -pub struct CpuUpdateRegistersFpUpdate; -impl Default for CpuUpdateRegistersFpUpdate { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersFpUpdate { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuUpdateRegistersFpUpdate { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 21 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let ap = current_step.get_main_evaluation_element(0, 17); - let fp = current_step.get_main_evaluation_element(0, 18); - let next_fp = next_step.get_main_evaluation_element(0, 18); - let dst = current_step.get_main_evaluation_element(0, 24); - - let opc_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - let opc_ret = current_step.get_main_evaluation_element(0, 13) - - two * current_step.get_main_evaluation_element(0, 14); - - let res = opc_ret * dst + opc_call * (ap + two) + (one - opc_ret - opc_call) * fp - next_fp; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -// cpu/update_registers/update_pc/pc_cond_negative: -pub struct CpuUpdateRegistersPcCondNegative; -impl Default for CpuUpdateRegistersPcCondNegative { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersPcCondNegative { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint - for CpuUpdateRegistersPcCondNegative -{ - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 23 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let one = Felt252::one(); - let two = Felt252::from(2); - - let t0 = current_step.get_main_evaluation_element(0, 30); - let pc = current_step.get_main_evaluation_element(0, 19); - let next_pc = next_step.get_main_evaluation_element(0, 19); - let op1 = current_step.get_main_evaluation_element(0, 26); - - let pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - let pc_abs = current_step.get_main_evaluation_element(0, 7) - - two * current_step.get_main_evaluation_element(0, 8); - let pc_rel = current_step.get_main_evaluation_element(0, 8) - - two * current_step.get_main_evaluation_element(0, 9); - let res = current_step.get_main_evaluation_element(0, 16); - - let res = t0 * (next_pc - (pc + op1)) + (one - pc_jnz) * next_pc - - ((one - pc_abs - pc_rel - pc_jnz) * (pc + frame_inst_size(current_step)) - + pc_abs * res - + pc_rel * (pc + res)); - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -pub struct CpuUpdateRegistersPcCondPositive; -impl Default for CpuUpdateRegistersPcCondPositive { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersPcCondPositive { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint - for CpuUpdateRegistersPcCondPositive -{ - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 22 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let two = Felt252::from(2); - - let t1 = current_step.get_main_evaluation_element(0, 31); - let pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - let pc = current_step.get_main_evaluation_element(0, 19); - let next_pc = next_step.get_main_evaluation_element(0, 19); - - let res = (t1 - pc_jnz) * (next_pc - (pc + frame_inst_size(current_step))); - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -//cpu/update_registers/update_pc/tmp0 -pub struct CpuUpdateRegistersUpdatePcTmp0; -impl Default for CpuUpdateRegistersUpdatePcTmp0 { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersUpdatePcTmp0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint - for CpuUpdateRegistersUpdatePcTmp0 -{ - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 24 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - let dst = current_step.get_main_evaluation_element(0, 24); - let t0 = current_step.get_main_evaluation_element(0, 30); - let pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - - let res = pc_jnz * dst - t0; - - transition_evaluations[self.constraint_idx()] = res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuUpdateRegistersUpdatePcTmp1; -impl Default for CpuUpdateRegistersUpdatePcTmp1 { - fn default() -> Self { - Self::new() - } -} - -impl CpuUpdateRegistersUpdatePcTmp1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint - for CpuUpdateRegistersUpdatePcTmp1 -{ - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 25 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let t1 = current_step.get_main_evaluation_element(0, 31); - let t0 = current_step.get_main_evaluation_element(0, 30); - let res = current_step.get_main_evaluation_element(0, 16); - - let transition_res = t0 * res - t1; - - transition_evaluations[self.constraint_idx()] = transition_res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOperandsOpsMul; -impl Default for CpuOperandsOpsMul { - fn default() -> Self { - Self::new() - } -} - -impl CpuOperandsOpsMul { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOperandsOpsMul { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 26 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let mul = current_step.get_main_evaluation_element(0, 32); - let op0 = current_step.get_main_evaluation_element(0, 25); - let op1 = current_step.get_main_evaluation_element(0, 26); - - transition_evaluations[self.constraint_idx()] = mul - op0 * op1; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -// cpu/operands/res -pub struct CpuOperandsRes; -impl Default for CpuOperandsRes { - fn default() -> Self { - Self::new() - } -} - -impl CpuOperandsRes { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOperandsRes { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 27 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let one = Felt252::one(); - let two = Felt252::from(2); - - let mul = current_step.get_main_evaluation_element(0, 32); - let op0 = current_step.get_main_evaluation_element(0, 25); - let op1 = current_step.get_main_evaluation_element(0, 26); - let res = current_step.get_main_evaluation_element(0, 16); - - let res_add = current_step.get_main_evaluation_element(0, 5) - - two * current_step.get_main_evaluation_element(0, 6); - let res_mul = current_step.get_main_evaluation_element(0, 6) - - two * current_step.get_main_evaluation_element(0, 7); - let pc_jnz = current_step.get_main_evaluation_element(0, 9) - - two * current_step.get_main_evaluation_element(0, 10); - - let transition_res = - res_add * (op0 + op1) + res_mul * mul + (one - res_add - res_mul - pc_jnz) * op1 - - (one - pc_jnz) * res; - - transition_evaluations[self.constraint_idx()] = transition_res; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -// cpu/opcodes/call/push_fp -pub struct CpuOpcodesCallPushFp; -impl Default for CpuOpcodesCallPushFp { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesCallPushFp { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesCallPushFp { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 28 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - - let opc_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - - let dst = current_step.get_main_evaluation_element(0, 24); - let fp = current_step.get_main_evaluation_element(0, 18); - - transition_evaluations[self.constraint_idx()] = opc_call * (dst - fp); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct CpuOpcodesCallPushPc; -impl Default for CpuOpcodesCallPushPc { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesCallPushPc { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesCallPushPc { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 29 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - - let opc_call = current_step.get_main_evaluation_element(0, 12) - - two * current_step.get_main_evaluation_element(0, 13); - - let op0 = current_step.get_main_evaluation_element(0, 25); - let pc = current_step.get_main_evaluation_element(0, 19); - - transition_evaluations[self.constraint_idx()] = - opc_call * (op0 - (pc + frame_inst_size(current_step))); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -// cpu/opcodes/assert_eq/assert_eq -pub struct CpuOpcodesAssertEq; -impl Default for CpuOpcodesAssertEq { - fn default() -> Self { - Self::new() - } -} - -impl CpuOpcodesAssertEq { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for CpuOpcodesAssertEq { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 30 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let two = Felt252::from(2); - - let opc_aeq = current_step.get_main_evaluation_element(0, 14) - - two * current_step.get_main_evaluation_element(0, 15); - let dst = current_step.get_main_evaluation_element(0, 24); - let res = current_step.get_main_evaluation_element(0, 16); - - transition_evaluations[self.constraint_idx()] = opc_aeq * (dst - res) - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -// memory/diff_is_bit -pub struct MemoryDiffIsBit0; -impl Default for MemoryDiffIsBit0 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryDiffIsBit0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryDiffIsBit0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 31 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_0 = current_step.get_aux_evaluation_element(0, 4); - let mem_addr_sorted_1 = current_step.get_aux_evaluation_element(0, 5); - - transition_evaluations[self.constraint_idx()] = - (mem_addr_sorted_0 - mem_addr_sorted_1) * (mem_addr_sorted_1 - mem_addr_sorted_0 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryDiffIsBit1; -impl Default for MemoryDiffIsBit1 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryDiffIsBit1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryDiffIsBit1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 32 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_1 = current_step.get_aux_evaluation_element(0, 5); - let mem_addr_sorted_2 = current_step.get_aux_evaluation_element(0, 6); - - transition_evaluations[self.constraint_idx()] = - (mem_addr_sorted_1 - mem_addr_sorted_2) * (mem_addr_sorted_2 - mem_addr_sorted_1 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} -pub struct MemoryDiffIsBit2; -impl Default for MemoryDiffIsBit2 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryDiffIsBit2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryDiffIsBit2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 33 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_2 = current_step.get_aux_evaluation_element(0, 6); - let mem_addr_sorted_3 = current_step.get_aux_evaluation_element(0, 7); - - transition_evaluations[self.constraint_idx()] = - (mem_addr_sorted_2 - mem_addr_sorted_3) * (mem_addr_sorted_3 - mem_addr_sorted_2 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} -pub struct MemoryDiffIsBit3; -impl Default for MemoryDiffIsBit3 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryDiffIsBit3 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryDiffIsBit3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 34 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_3 = current_step.get_aux_evaluation_element(0, 7); - let mem_addr_sorted_4 = current_step.get_aux_evaluation_element(0, 8); - - transition_evaluations[self.constraint_idx()] = - (mem_addr_sorted_3 - mem_addr_sorted_4) * (mem_addr_sorted_4 - mem_addr_sorted_3 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} -pub struct MemoryDiffIsBit4; -impl Default for MemoryDiffIsBit4 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryDiffIsBit4 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryDiffIsBit4 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 35 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let one = Felt252::one(); - - let next_mem_addr_sorted_0 = next_step.get_aux_evaluation_element(0, 4); - let mem_addr_sorted_4 = current_step.get_aux_evaluation_element(0, 8); - - transition_evaluations[self.constraint_idx()] = (mem_addr_sorted_4 - - next_mem_addr_sorted_0) - * (next_mem_addr_sorted_0 - mem_addr_sorted_4 - one); - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -// memory/is_func (single-valued) -pub struct MemoryIsFunc0; -impl Default for MemoryIsFunc0 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryIsFunc0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryIsFunc0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 36 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_0 = current_step.get_aux_evaluation_element(0, 4); - let mem_addr_sorted_1 = current_step.get_aux_evaluation_element(0, 5); - - let mem_val_sorted_0 = current_step.get_aux_evaluation_element(0, 9); - let mem_val_sorted_1 = current_step.get_aux_evaluation_element(0, 10); - - transition_evaluations[self.constraint_idx()] = - (mem_val_sorted_0 - mem_val_sorted_1) * (mem_addr_sorted_1 - mem_addr_sorted_0 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryIsFunc1; -impl Default for MemoryIsFunc1 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryIsFunc1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryIsFunc1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 37 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_1 = current_step.get_aux_evaluation_element(0, 5); - let mem_addr_sorted_2 = current_step.get_aux_evaluation_element(0, 6); - - let mem_val_sorted_1 = current_step.get_aux_evaluation_element(0, 10); - let mem_val_sorted_2 = current_step.get_aux_evaluation_element(0, 11); - - transition_evaluations[self.constraint_idx()] = - (mem_val_sorted_1 - mem_val_sorted_2) * (mem_addr_sorted_2 - mem_addr_sorted_1 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryIsFunc2; -impl Default for MemoryIsFunc2 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryIsFunc2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryIsFunc2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 38 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_2 = current_step.get_aux_evaluation_element(0, 6); - let mem_addr_sorted_3 = current_step.get_aux_evaluation_element(0, 7); - - let mem_val_sorted_2 = current_step.get_aux_evaluation_element(0, 11); - let mem_val_sorted_3 = current_step.get_aux_evaluation_element(0, 12); - - transition_evaluations[self.constraint_idx()] = - (mem_val_sorted_2 - mem_val_sorted_3) * (mem_addr_sorted_3 - mem_addr_sorted_2 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryIsFunc3; -impl Default for MemoryIsFunc3 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryIsFunc3 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryIsFunc3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 39 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let one = Felt252::one(); - - let mem_addr_sorted_3 = current_step.get_aux_evaluation_element(0, 7); - let mem_addr_sorted_4 = current_step.get_aux_evaluation_element(0, 8); - - let mem_val_sorted_3 = current_step.get_aux_evaluation_element(0, 12); - let mem_val_sorted_4 = current_step.get_aux_evaluation_element(0, 13); - - transition_evaluations[self.constraint_idx()] = - (mem_val_sorted_3 - mem_val_sorted_4) * (mem_addr_sorted_4 - mem_addr_sorted_3 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} -pub struct MemoryIsFunc4; -impl Default for MemoryIsFunc4 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryIsFunc4 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryIsFunc4 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 40 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let one = Felt252::one(); - - let next_mem_addr_sorted_0 = next_step.get_aux_evaluation_element(0, 4); - let mem_addr_sorted_4 = current_step.get_aux_evaluation_element(0, 8); - - let next_mem_val_sorted_0 = next_step.get_aux_evaluation_element(0, 9); - let mem_val_sorted_4 = current_step.get_aux_evaluation_element(0, 13); - - transition_evaluations[self.constraint_idx()] = (mem_val_sorted_4 - next_mem_val_sorted_0) - * (next_mem_addr_sorted_0 - mem_addr_sorted_4 - one); - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -// memory/multi_column_perm/perm/step0 -pub struct MemoryMultiColumnPermStep0_0; -impl Default for MemoryMultiColumnPermStep0_0 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryMultiColumnPermStep0_0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryMultiColumnPermStep0_0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 41 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let alpha = rap_challenges[0]; - let z = rap_challenges[1]; - - let a1 = current_step.get_main_evaluation_element(0, 20); - let v1 = current_step.get_main_evaluation_element(0, 24); - - let p0 = current_step.get_aux_evaluation_element(0, 14); - let ap1 = current_step.get_aux_evaluation_element(0, 5); - let vp1 = current_step.get_aux_evaluation_element(0, 10); - let p1 = current_step.get_aux_evaluation_element(0, 15); - - transition_evaluations[self.constraint_idx()] = - (z - (ap1 + alpha * vp1)) * p1 - (z - (a1 + alpha * v1)) * p0; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryMultiColumnPermStep0_1; -impl Default for MemoryMultiColumnPermStep0_1 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryMultiColumnPermStep0_1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryMultiColumnPermStep0_1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 42 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let alpha = rap_challenges[0]; - let z = rap_challenges[1]; - - let a2 = current_step.get_main_evaluation_element(0, 21); - let v2 = current_step.get_main_evaluation_element(0, 25); - - let p1 = current_step.get_aux_evaluation_element(0, 15); - let ap2 = current_step.get_aux_evaluation_element(0, 6); - let vp2 = current_step.get_aux_evaluation_element(0, 11); - let p2 = current_step.get_aux_evaluation_element(0, 16); - - transition_evaluations[self.constraint_idx()] = - (z - (ap2 + alpha * vp2)) * p2 - (z - (a2 + alpha * v2)) * p1; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryMultiColumnPermStep0_2; -impl Default for MemoryMultiColumnPermStep0_2 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryMultiColumnPermStep0_2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryMultiColumnPermStep0_2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 43 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let alpha = rap_challenges[0]; - let z = rap_challenges[1]; - let a3 = current_step.get_main_evaluation_element(0, 22); - let v3 = current_step.get_main_evaluation_element(0, 26); - - let p2 = current_step.get_aux_evaluation_element(0, 16); - let ap3 = current_step.get_aux_evaluation_element(0, 7); - let vp3 = current_step.get_aux_evaluation_element(0, 12); - let p3 = current_step.get_aux_evaluation_element(0, 17); - - transition_evaluations[self.constraint_idx()] = - (z - (ap3 + alpha * vp3)) * p3 - (z - (a3 + alpha * v3)) * p2; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryMultiColumnPermStep0_3; -impl Default for MemoryMultiColumnPermStep0_3 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryMultiColumnPermStep0_3 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryMultiColumnPermStep0_3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 44 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let alpha = rap_challenges[0]; - let z = rap_challenges[1]; - let a4 = current_step.get_main_evaluation_element(0, 33); - let v4 = current_step.get_main_evaluation_element(0, 34); - - let p3 = current_step.get_aux_evaluation_element(0, 17); - let p4 = current_step.get_aux_evaluation_element(0, 18); - let ap4 = current_step.get_aux_evaluation_element(0, 8); - let vp4 = current_step.get_aux_evaluation_element(0, 13); - - transition_evaluations[self.constraint_idx()] = - (z - (ap4 + alpha * vp4)) * p4 - (z - (a4 + alpha * v4)) * p3; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct MemoryMultiColumnPermStep0_4; -impl Default for MemoryMultiColumnPermStep0_4 { - fn default() -> Self { - Self::new() - } -} - -impl MemoryMultiColumnPermStep0_4 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for MemoryMultiColumnPermStep0_4 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 45 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let alpha = rap_challenges[0]; - let z = rap_challenges[1]; - let next_a0 = next_step.get_main_evaluation_element(0, 19); - let next_v0 = next_step.get_main_evaluation_element(0, 23); - - let next_ap0 = next_step.get_aux_evaluation_element(0, 4); - let next_vp0 = next_step.get_aux_evaluation_element(0, 9); - let next_p0 = next_step.get_aux_evaluation_element(0, 14); - let p4 = current_step.get_aux_evaluation_element(0, 18); - - transition_evaluations[self.constraint_idx()] = - (z - (next_ap0 + alpha * next_vp0)) * next_p0 - (z - (next_a0 + alpha * next_v0)) * p4; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -// rc16/diff_is_bit -pub struct Rc16DiffIsBit0; -impl Default for Rc16DiffIsBit0 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16DiffIsBit0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16DiffIsBit0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 46 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let one = Felt252::one(); - - let rc_col_1 = current_step.get_aux_evaluation_element(0, 0); - let rc_col_2 = current_step.get_aux_evaluation_element(0, 1); - - transition_evaluations[self.constraint_idx()] = - (rc_col_1 - rc_col_2) * (rc_col_2 - rc_col_1 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16DiffIsBit1; -impl Default for Rc16DiffIsBit1 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16DiffIsBit1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16DiffIsBit1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 47 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let one = Felt252::one(); - - let rc_col_2 = current_step.get_aux_evaluation_element(0, 1); - let rc_col_3 = current_step.get_aux_evaluation_element(0, 2); - - transition_evaluations[self.constraint_idx()] = - (rc_col_2 - rc_col_3) * (rc_col_3 - rc_col_2 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16DiffIsBit2; -impl Default for Rc16DiffIsBit2 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16DiffIsBit2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16DiffIsBit2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 48 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let one = Felt252::one(); - - let rc_col_3 = current_step.get_aux_evaluation_element(0, 2); - let rc_col_4 = current_step.get_aux_evaluation_element(0, 3); - - transition_evaluations[self.constraint_idx()] = - (rc_col_3 - rc_col_4) * (rc_col_4 - rc_col_3 - one); - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16DiffIsBit3; -impl Default for Rc16DiffIsBit3 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16DiffIsBit3 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16DiffIsBit3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 49 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - _rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - let one = Felt252::one(); - - let rc_col_4 = current_step.get_aux_evaluation_element(0, 3); - let next_rc_col_1 = next_step.get_aux_evaluation_element(0, 0); - - transition_evaluations[self.constraint_idx()] = - (rc_col_4 - next_rc_col_1) * (next_rc_col_1 - rc_col_4 - one); - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -// rc16/perm/step0 -pub struct Rc16PermStep0_0; -impl Default for Rc16PermStep0_0 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16PermStep0_0 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16PermStep0_0 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 50 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let z = rap_challenges[2]; - let a1 = current_step.get_main_evaluation_element(0, 28); - - let ap1 = current_step.get_aux_evaluation_element(0, 1); - let p1 = current_step.get_aux_evaluation_element(0, 20); - let p0 = current_step.get_aux_evaluation_element(0, 19); - - transition_evaluations[self.constraint_idx()] = (z - ap1) * p1 - (z - a1) * p0; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16PermStep0_1; -impl Default for Rc16PermStep0_1 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16PermStep0_1 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16PermStep0_1 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 51 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let z = rap_challenges[2]; - - let a2 = current_step.get_main_evaluation_element(0, 29); - - let ap2 = current_step.get_aux_evaluation_element(0, 2); - let p2 = current_step.get_aux_evaluation_element(0, 21); - let p1 = current_step.get_aux_evaluation_element(0, 20); - - transition_evaluations[self.constraint_idx()] = (z - ap2) * p2 - (z - a2) * p1; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16PermStep0_2; -impl Default for Rc16PermStep0_2 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16PermStep0_2 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16PermStep0_2 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 52 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - - let z = rap_challenges[2]; - let a3 = current_step.get_main_evaluation_element(0, 35); - - let ap3 = current_step.get_aux_evaluation_element(0, 3); - let p3 = current_step.get_aux_evaluation_element(0, 22); - let p2 = current_step.get_aux_evaluation_element(0, 21); - - transition_evaluations[self.constraint_idx()] = (z - ap3) * p3 - (z - a3) * p2; - } - - fn end_exemptions(&self) -> usize { - 0 - } -} - -pub struct Rc16PermStep0_3; -impl Default for Rc16PermStep0_3 { - fn default() -> Self { - Self::new() - } -} - -impl Rc16PermStep0_3 { - pub fn new() -> Self { - Self - } -} - -impl TransitionConstraint for Rc16PermStep0_3 { - fn degree(&self) -> usize { - 2 - } - - fn constraint_idx(&self) -> usize { - 53 - } - - fn evaluate( - &self, - frame: &Frame, - transition_evaluations: &mut [Felt252], - _periodic_values: &[Felt252], - rap_challenges: &[Felt252], - ) { - let current_step = frame.get_evaluation_step(0); - let next_step = frame.get_evaluation_step(1); - - let z = rap_challenges[2]; - - let p3 = current_step.get_aux_evaluation_element(0, 22); - - let next_a0 = next_step.get_main_evaluation_element(0, 27); - let next_ap0 = next_step.get_aux_evaluation_element(0, 0); - - let next_p0 = next_step.get_aux_evaluation_element(0, 19); - - transition_evaluations[self.constraint_idx()] = - (z - next_ap0) * next_p0 - (z - next_a0) * p3; - } - - fn end_exemptions(&self) -> usize { - 1 - } -} - -fn frame_inst_size(step: &TableView) -> Felt252 { - let op1_val = step.get_main_evaluation_element(0, 2) - - Felt252::from(2) * step.get_main_evaluation_element(0, 3); - op1_val + Felt252::one() -} diff --git a/provers/cairo/src/wasm_wrappers.rs b/provers/cairo/src/wasm_wrappers.rs deleted file mode 100644 index 7ab9f3c14..000000000 --- a/provers/cairo/src/wasm_wrappers.rs +++ /dev/null @@ -1,73 +0,0 @@ -use super::air::CairoAIR; -use lambdaworks_math::field::element::FieldElement; -use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; -use serde::{Deserialize, Serialize}; -use stark_platinum_prover::proof::options::ProofOptions; -use stark_platinum_prover::proof::options::SecurityLevel; -use stark_platinum_prover::transcript::StoneProverTranscript; -use stark_platinum_prover::verifier::{IsStarkVerifier, Verifier}; -use std::collections::HashMap; -use wasm_bindgen::prelude::wasm_bindgen; - -#[wasm_bindgen] -#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Hash)] -pub struct FE(FieldElement); - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct MemoryMap(HashMap); - -#[wasm_bindgen] -pub fn verify_cairo_proof_wasm(proof_bytes: &[u8], proof_options: &ProofOptions) -> bool { - let bytes = proof_bytes; - - // This logic is the same as main verify, with only error handling changing. In wasm, we simply return a false if the proof is invalid, instead of rising an error. - - // Proof len was stored as an u32, 4u8 needs to be read - let proof_len = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) as usize; - - let bytes = &bytes[4..]; - if bytes.len() < proof_len { - return false; - } - - let Ok((proof, _)) = - bincode::serde::decode_from_slice(&bytes[0..proof_len], bincode::config::standard()) - else { - return false; - }; - let bytes = &bytes[proof_len..]; - - let Ok((pub_inputs, _)) = bincode::serde::decode_from_slice(bytes, bincode::config::standard()) - else { - return false; - }; - - Verifier::::verify( - &proof, - &pub_inputs, - proof_options, - StoneProverTranscript::new(&[]), - ) -} - -/// WASM Function for verifying a proof with default 100 bits of security -#[wasm_bindgen] -pub fn verify_cairo_proof_wasm_100_bits(proof_bytes: &[u8]) -> bool { - let proof_options = ProofOptions::new_secure(SecurityLevel::Conjecturable100Bits, 3); - verify_cairo_proof_wasm(proof_bytes, &proof_options) -} - -#[wasm_bindgen] -pub fn new_proof_options( - blowup_factor: u8, - fri_number_of_queries: usize, - coset_offset: usize, - grinding_factor: u8, -) -> ProofOptions { - ProofOptions { - blowup_factor, - fri_number_of_queries, - coset_offset: coset_offset as u64, - grinding_factor, - } -} diff --git a/provers/cairo/tests/wasm.rs b/provers/cairo/tests/wasm.rs deleted file mode 100644 index eb8fb6604..000000000 --- a/provers/cairo/tests/wasm.rs +++ /dev/null @@ -1,1238 +0,0 @@ -use wasm_bindgen_test::wasm_bindgen_test_configure; -wasm_bindgen_test_configure!(run_in_browser); - -#[cfg(feature = "wasm")] -use cairo_platinum_prover::wasm_wrappers::verify_cairo_proof_wasm; -#[cfg(feature = "wasm")] -use stark_platinum_prover::proof::options::ProofOptions; - -#[cfg(feature = "wasm")] -use wasm_bindgen_test::*; - -#[cfg(feature = "wasm")] -#[wasm_bindgen_test] -#[test] -fn test_prove_cairo1_program_wasm() { - let proof_options = ProofOptions::default_test_options(); - assert!(verify_cairo_proof_wasm(&PROOF, &proof_options)); -} - -// Test case is fibo5, with default test options -#[cfg(feature = "wasm")] -static PROOF: [u8; 25527] = [ - 189, 90, 0, 0, 64, 34, 150, 252, 123, 41, 36, 58, 219, 76, 25, 24, 145, 52, 128, 169, 121, 212, - 127, 31, 128, 230, 237, 60, 212, 165, 171, 81, 190, 191, 157, 241, 200, 1, 77, 31, 232, 212, - 215, 170, 34, 124, 137, 195, 171, 208, 228, 24, 74, 34, 237, 107, 135, 106, 205, 168, 33, 72, - 193, 202, 8, 15, 250, 12, 38, 185, 118, 32, 4, 121, 119, 154, 112, 215, 149, 181, 135, 19, 126, - 111, 29, 70, 31, 188, 18, 213, 57, 174, 39, 158, 20, 84, 21, 255, 108, 8, 130, 181, 210, 188, - 32, 6, 160, 9, 128, 25, 11, 118, 22, 20, 151, 71, 31, 175, 86, 16, 174, 137, 223, 219, 241, - 181, 35, 4, 196, 138, 91, 86, 112, 137, 228, 116, 81, 32, 7, 107, 149, 38, 34, 86, 96, 114, - 159, 34, 99, 135, 158, 58, 25, 31, 76, 30, 86, 40, 212, 147, 139, 195, 62, 99, 10, 139, 2, 32, - 214, 196, 32, 6, 108, 34, 191, 254, 254, 228, 247, 135, 134, 229, 235, 224, 97, 77, 120, 157, - 43, 153, 217, 41, 102, 201, 99, 134, 117, 228, 144, 48, 163, 25, 129, 32, 2, 20, 45, 228, 132, - 42, 246, 70, 86, 114, 189, 79, 91, 197, 193, 77, 249, 25, 48, 253, 126, 70, 191, 158, 197, 112, - 103, 222, 171, 146, 253, 45, 32, 7, 117, 162, 64, 207, 150, 67, 187, 96, 148, 96, 38, 49, 9, - 133, 44, 90, 236, 197, 169, 22, 115, 1, 96, 121, 62, 95, 14, 18, 245, 96, 28, 32, 5, 99, 63, - 92, 105, 2, 109, 50, 41, 189, 169, 18, 51, 142, 198, 244, 225, 45, 184, 128, 162, 195, 173, - 132, 26, 158, 29, 73, 185, 108, 189, 223, 32, 6, 177, 159, 174, 52, 129, 54, 161, 148, 222, - 212, 137, 25, 199, 99, 122, 112, 150, 220, 64, 81, 97, 214, 194, 13, 79, 14, 164, 220, 182, 94, - 240, 32, 7, 21, 63, 67, 83, 232, 93, 14, 9, 158, 191, 21, 234, 220, 250, 2, 20, 252, 77, 157, - 2, 107, 56, 219, 24, 198, 119, 137, 150, 248, 184, 108, 32, 6, 118, 104, 204, 170, 167, 72, 36, - 24, 28, 178, 178, 199, 153, 3, 48, 248, 109, 16, 177, 203, 221, 79, 51, 65, 123, 50, 17, 24, - 186, 245, 98, 32, 6, 53, 4, 218, 106, 98, 29, 135, 172, 151, 167, 87, 84, 29, 48, 173, 143, - 159, 203, 207, 109, 62, 43, 234, 243, 200, 173, 51, 81, 205, 214, 159, 32, 1, 192, 54, 174, - 176, 150, 192, 232, 159, 124, 165, 164, 227, 190, 10, 213, 99, 13, 175, 251, 178, 63, 130, 157, - 229, 200, 157, 4, 248, 245, 91, 170, 32, 3, 131, 77, 129, 155, 122, 112, 105, 14, 166, 108, 44, - 230, 88, 128, 192, 101, 208, 9, 193, 199, 170, 102, 165, 219, 33, 6, 149, 50, 190, 136, 4, 32, - 1, 166, 22, 90, 183, 236, 147, 229, 114, 124, 118, 30, 172, 157, 47, 152, 43, 185, 156, 176, - 233, 211, 41, 241, 244, 91, 35, 247, 220, 48, 167, 119, 32, 0, 143, 122, 153, 149, 158, 11, - 167, 120, 109, 143, 224, 180, 71, 224, 16, 242, 141, 173, 213, 78, 163, 226, 115, 12, 76, 130, - 51, 22, 181, 220, 175, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 2, 1, 253, 138, 34, 207, 195, 158, 101, 246, 72, 80, 69, 234, - 134, 69, 254, 0, 214, 200, 65, 117, 252, 210, 179, 241, 125, 139, 80, 132, 22, 88, 32, 5, 207, - 6, 122, 136, 121, 97, 74, 64, 92, 10, 82, 129, 253, 207, 93, 27, 141, 1, 155, 169, 154, 254, - 206, 37, 170, 143, 226, 127, 127, 197, 136, 32, 2, 82, 215, 180, 74, 233, 38, 140, 152, 162, - 68, 165, 53, 110, 9, 215, 1, 145, 213, 78, 167, 109, 84, 4, 109, 31, 245, 125, 198, 84, 65, - 158, 32, 6, 254, 118, 48, 225, 227, 141, 219, 18, 3, 186, 152, 178, 114, 191, 66, 55, 89, 219, - 95, 200, 151, 29, 176, 74, 41, 179, 109, 99, 230, 201, 88, 32, 6, 54, 190, 65, 189, 147, 32, - 77, 11, 90, 84, 204, 243, 122, 213, 92, 228, 209, 124, 145, 16, 62, 177, 252, 154, 93, 164, 93, - 254, 68, 192, 203, 32, 7, 146, 93, 121, 26, 128, 203, 73, 35, 188, 123, 51, 179, 189, 238, 11, - 106, 121, 76, 173, 19, 223, 23, 158, 122, 246, 192, 227, 134, 2, 231, 8, 32, 0, 158, 30, 24, - 198, 212, 205, 150, 208, 38, 174, 245, 134, 86, 168, 184, 120, 219, 209, 14, 217, 183, 243, - 240, 193, 102, 22, 97, 21, 230, 145, 150, 32, 4, 215, 231, 29, 42, 198, 22, 162, 226, 157, 128, - 71, 137, 216, 168, 228, 206, 159, 159, 52, 172, 88, 144, 103, 86, 202, 201, 230, 40, 78, 112, - 45, 32, 5, 235, 155, 127, 149, 142, 77, 54, 242, 17, 239, 182, 3, 107, 250, 74, 164, 113, 37, - 129, 249, 242, 46, 29, 220, 59, 254, 100, 15, 23, 32, 202, 32, 0, 100, 208, 10, 200, 88, 205, - 233, 28, 178, 96, 76, 200, 165, 11, 14, 9, 60, 200, 108, 74, 226, 251, 191, 116, 36, 106, 38, - 238, 105, 49, 59, 32, 3, 109, 137, 42, 78, 68, 171, 105, 86, 141, 182, 33, 18, 186, 138, 195, - 43, 158, 64, 240, 244, 44, 15, 82, 62, 95, 159, 208, 99, 128, 120, 166, 32, 6, 80, 221, 32, - 107, 188, 148, 20, 172, 97, 46, 213, 33, 96, 119, 194, 172, 209, 57, 171, 231, 161, 116, 77, - 146, 91, 127, 153, 116, 194, 6, 119, 32, 7, 95, 148, 33, 184, 38, 17, 124, 108, 165, 3, 157, - 11, 105, 123, 140, 78, 201, 252, 56, 201, 189, 40, 44, 160, 20, 181, 223, 97, 246, 63, 212, 32, - 4, 199, 196, 123, 36, 185, 76, 235, 127, 222, 243, 141, 18, 227, 51, 51, 179, 61, 186, 186, 17, - 65, 133, 204, 48, 129, 249, 79, 59, 212, 119, 134, 32, 1, 14, 184, 241, 108, 147, 105, 134, - 173, 126, 26, 113, 63, 210, 43, 210, 50, 231, 28, 98, 224, 126, 88, 254, 170, 63, 113, 191, - 174, 199, 229, 91, 32, 2, 188, 189, 236, 183, 2, 74, 99, 103, 10, 113, 112, 169, 116, 72, 218, - 15, 195, 180, 92, 244, 7, 8, 151, 187, 53, 116, 18, 145, 165, 235, 146, 32, 2, 213, 207, 119, - 50, 184, 15, 218, 181, 76, 123, 149, 88, 220, 220, 174, 163, 206, 82, 138, 209, 248, 253, 254, - 252, 104, 112, 41, 95, 243, 234, 85, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 254, 239, 253, 240, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 239, 255, 225, 32, 2, 58, 120, 103, 31, 144, 59, 36, 56, 216, 9, 143, 28, 152, 182, 24, - 101, 45, 40, 210, 92, 137, 3, 122, 137, 71, 129, 229, 131, 142, 200, 44, 32, 4, 95, 194, 144, - 22, 191, 76, 52, 100, 111, 16, 86, 25, 205, 60, 214, 40, 4, 73, 84, 53, 241, 111, 62, 89, 113, - 219, 34, 79, 171, 193, 213, 32, 4, 95, 194, 144, 22, 191, 76, 52, 100, 111, 16, 86, 25, 205, - 60, 214, 40, 4, 73, 84, 53, 241, 111, 62, 89, 113, 219, 34, 79, 171, 193, 213, 32, 4, 95, 194, - 144, 22, 191, 76, 52, 100, 111, 16, 86, 25, 205, 60, 214, 40, 4, 73, 84, 53, 241, 111, 62, 89, - 113, 219, 34, 79, 171, 193, 213, 32, 6, 170, 73, 20, 201, 41, 221, 95, 49, 88, 98, 198, 144, - 97, 178, 19, 20, 21, 54, 82, 199, 12, 45, 76, 215, 6, 123, 35, 238, 137, 202, 40, 32, 7, 100, - 98, 115, 53, 180, 216, 211, 207, 130, 160, 111, 216, 133, 121, 40, 24, 215, 122, 245, 214, 76, - 187, 71, 161, 160, 17, 97, 55, 180, 8, 5, 32, 2, 20, 170, 80, 81, 77, 23, 100, 85, 178, 255, - 127, 197, 138, 93, 120, 122, 114, 55, 153, 40, 18, 61, 181, 194, 255, 250, 174, 72, 182, 102, - 209, 32, 7, 20, 154, 141, 85, 62, 150, 185, 19, 107, 229, 104, 250, 70, 91, 203, 144, 9, 161, - 212, 234, 206, 29, 214, 118, 61, 199, 234, 111, 121, 255, 145, 32, 5, 113, 191, 41, 145, 51, - 220, 90, 222, 148, 12, 129, 249, 149, 236, 127, 207, 145, 201, 137, 53, 197, 218, 85, 9, 95, - 116, 43, 126, 1, 50, 243, 32, 7, 41, 143, 167, 119, 191, 45, 94, 57, 127, 51, 171, 183, 74, - 209, 143, 108, 123, 105, 127, 183, 37, 13, 103, 64, 232, 8, 200, 130, 138, 61, 78, 32, 7, 179, - 106, 203, 33, 8, 218, 190, 122, 33, 209, 80, 113, 38, 227, 184, 137, 24, 216, 11, 254, 221, - 197, 142, 70, 5, 141, 108, 0, 183, 75, 60, 32, 1, 117, 211, 84, 179, 151, 225, 227, 192, 48, - 144, 91, 223, 191, 221, 189, 250, 107, 130, 65, 174, 248, 46, 237, 4, 150, 1, 161, 15, 237, - 175, 140, 32, 7, 151, 193, 227, 109, 196, 148, 8, 12, 2, 93, 154, 254, 190, 168, 126, 115, 176, - 87, 244, 18, 245, 176, 255, 184, 74, 60, 134, 197, 64, 47, 198, 32, 1, 117, 234, 61, 180, 193, - 236, 53, 166, 68, 245, 7, 239, 133, 162, 169, 113, 184, 48, 142, 65, 35, 165, 252, 108, 157, - 51, 214, 79, 106, 127, 100, 32, 1, 55, 188, 132, 102, 25, 136, 86, 128, 254, 76, 150, 65, 68, - 67, 141, 141, 199, 5, 54, 5, 54, 193, 66, 219, 226, 231, 176, 237, 235, 86, 24, 32, 3, 13, 246, - 153, 18, 135, 58, 85, 177, 66, 112, 254, 233, 238, 154, 39, 78, 236, 149, 51, 145, 161, 115, - 190, 55, 59, 3, 153, 248, 255, 14, 59, 32, 4, 44, 148, 208, 135, 107, 26, 190, 55, 245, 96, - 224, 168, 146, 28, 132, 121, 112, 244, 136, 170, 187, 113, 14, 84, 158, 238, 144, 99, 64, 212, - 162, 32, 6, 3, 108, 124, 197, 209, 187, 234, 214, 106, 11, 99, 173, 24, 108, 50, 113, 93, 111, - 81, 184, 68, 126, 53, 149, 82, 4, 249, 241, 1, 38, 45, 32, 4, 99, 217, 80, 21, 33, 240, 160, - 192, 206, 148, 125, 201, 15, 226, 223, 205, 54, 196, 69, 238, 196, 211, 131, 106, 163, 155, 71, - 254, 69, 148, 35, 32, 2, 48, 20, 156, 33, 221, 241, 152, 186, 21, 217, 133, 210, 195, 96, 76, - 182, 89, 195, 57, 141, 140, 194, 34, 98, 73, 184, 74, 158, 222, 233, 204, 32, 2, 104, 146, 122, - 157, 155, 177, 23, 184, 43, 123, 16, 201, 28, 174, 245, 3, 129, 93, 122, 56, 72, 221, 119, 158, - 48, 136, 129, 156, 146, 129, 85, 32, 7, 204, 154, 228, 196, 116, 47, 11, 22, 136, 232, 70, 49, - 217, 80, 27, 27, 71, 148, 85, 106, 137, 239, 44, 60, 142, 255, 114, 199, 138, 131, 115, 32, 0, - 109, 148, 114, 107, 9, 10, 135, 133, 203, 14, 200, 143, 22, 176, 132, 91, 191, 120, 231, 4, 11, - 27, 29, 2, 144, 66, 74, 172, 180, 238, 173, 32, 5, 41, 106, 199, 66, 209, 86, 79, 26, 114, 96, - 115, 160, 206, 94, 45, 101, 109, 218, 61, 240, 250, 236, 254, 99, 11, 208, 173, 123, 237, 172, - 218, 32, 7, 195, 15, 52, 113, 31, 59, 106, 153, 94, 78, 59, 116, 234, 101, 79, 99, 50, 165, 71, - 164, 242, 93, 229, 173, 68, 76, 63, 130, 180, 245, 171, 32, 7, 178, 233, 172, 78, 145, 162, - 101, 232, 61, 41, 82, 127, 140, 193, 65, 50, 22, 164, 191, 140, 197, 45, 169, 27, 70, 249, 29, - 104, 25, 145, 54, 32, 5, 103, 27, 203, 24, 80, 17, 106, 37, 200, 66, 30, 240, 30, 10, 130, 161, - 220, 169, 53, 232, 88, 202, 248, 230, 100, 254, 37, 91, 86, 106, 130, 32, 1, 7, 154, 215, 176, - 200, 223, 248, 219, 75, 86, 84, 157, 153, 63, 218, 154, 146, 99, 255, 244, 68, 127, 59, 3, 133, - 63, 233, 75, 12, 125, 229, 32, 4, 162, 25, 132, 194, 188, 89, 153, 243, 148, 200, 111, 120, - 234, 187, 113, 250, 211, 203, 196, 216, 19, 241, 186, 152, 174, 93, 135, 96, 219, 84, 120, 32, - 3, 94, 57, 26, 147, 93, 208, 42, 251, 160, 44, 253, 234, 225, 221, 209, 83, 232, 56, 222, 73, - 86, 22, 34, 133, 66, 159, 217, 36, 198, 149, 248, 32, 1, 175, 28, 141, 73, 174, 232, 21, 125, - 208, 22, 126, 245, 112, 238, 232, 169, 244, 28, 111, 36, 171, 11, 17, 66, 161, 79, 236, 146, - 99, 74, 252, 32, 6, 105, 207, 161, 80, 227, 125, 57, 107, 219, 234, 242, 8, 57, 180, 6, 79, - 244, 114, 176, 90, 196, 160, 93, 93, 148, 250, 136, 178, 122, 77, 203, 32, 5, 170, 248, 163, - 232, 122, 43, 2, 147, 175, 63, 152, 67, 184, 111, 129, 199, 252, 147, 171, 35, 206, 159, 120, - 115, 29, 71, 80, 34, 233, 231, 67, 32, 5, 235, 92, 54, 78, 181, 54, 43, 197, 26, 242, 212, 164, - 133, 161, 32, 206, 244, 132, 107, 0, 119, 161, 192, 98, 107, 132, 45, 35, 61, 151, 241, 32, 1, - 52, 115, 199, 154, 130, 145, 138, 77, 44, 24, 92, 225, 232, 60, 191, 17, 133, 174, 225, 68, - 248, 253, 109, 190, 219, 85, 222, 106, 223, 199, 237, 32, 4, 65, 124, 175, 73, 120, 63, 43, 8, - 5, 100, 6, 79, 135, 103, 228, 149, 4, 66, 187, 228, 34, 215, 155, 81, 4, 227, 10, 152, 83, 210, - 90, 32, 2, 79, 92, 69, 142, 186, 27, 253, 104, 116, 175, 206, 98, 172, 37, 88, 202, 4, 207, 66, - 55, 197, 109, 23, 99, 221, 158, 135, 165, 106, 210, 221, 32, 2, 185, 239, 125, 115, 105, 23, - 36, 225, 46, 55, 153, 190, 215, 79, 62, 95, 252, 204, 25, 228, 81, 209, 96, 110, 51, 33, 214, - 59, 254, 17, 187, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 6, 115, 185, 251, 251, 2, 194, 113, 34, 165, 158, 201, 2, 155, 58, - 231, 207, 183, 88, 168, 36, 176, 229, 83, 109, 5, 228, 104, 251, 149, 0, 169, 32, 0, 23, 30, - 73, 111, 138, 235, 54, 146, 59, 69, 100, 119, 174, 18, 9, 159, 47, 91, 41, 166, 49, 108, 197, - 98, 121, 163, 236, 57, 127, 71, 230, 32, 3, 135, 193, 17, 66, 204, 31, 13, 198, 104, 151, 87, - 201, 70, 48, 171, 93, 196, 213, 133, 72, 38, 70, 160, 168, 13, 131, 96, 7, 226, 139, 241, 32, - 0, 97, 102, 235, 176, 150, 14, 255, 3, 82, 45, 214, 73, 26, 71, 248, 125, 155, 45, 139, 124, - 80, 247, 214, 243, 124, 101, 179, 141, 154, 195, 162, 32, 6, 2, 0, 84, 32, 175, 214, 204, 21, - 56, 3, 253, 30, 16, 24, 127, 110, 182, 243, 196, 52, 84, 5, 188, 1, 231, 85, 219, 238, 138, - 212, 128, 32, 5, 41, 245, 43, 9, 88, 252, 140, 241, 50, 247, 88, 201, 134, 107, 10, 138, 185, - 129, 84, 20, 180, 247, 156, 48, 190, 41, 60, 144, 165, 148, 158, 32, 0, 128, 135, 202, 252, 45, - 176, 31, 143, 187, 108, 30, 148, 161, 37, 7, 111, 221, 225, 16, 14, 94, 38, 96, 113, 129, 116, - 34, 2, 216, 200, 159, 32, 6, 227, 189, 138, 109, 9, 174, 87, 133, 125, 196, 131, 133, 203, 175, - 233, 36, 232, 231, 106, 46, 254, 207, 133, 169, 31, 102, 114, 167, 133, 218, 49, 32, 0, 32, 35, - 156, 126, 100, 217, 21, 5, 4, 77, 161, 75, 187, 104, 12, 133, 33, 8, 191, 243, 252, 247, 101, - 117, 215, 71, 248, 98, 127, 216, 63, 32, 0, 115, 15, 50, 93, 55, 31, 152, 56, 32, 35, 75, 80, - 60, 95, 38, 34, 171, 102, 52, 111, 219, 210, 246, 116, 152, 47, 203, 146, 37, 25, 223, 32, 6, - 14, 95, 6, 196, 226, 244, 244, 239, 116, 1, 198, 58, 8, 219, 245, 5, 138, 203, 23, 67, 23, 84, - 232, 149, 164, 19, 227, 167, 195, 146, 206, 32, 7, 208, 64, 211, 244, 126, 177, 122, 187, 50, - 96, 64, 242, 176, 168, 204, 138, 69, 128, 232, 60, 106, 201, 93, 194, 23, 92, 253, 161, 90, 49, - 208, 32, 6, 0, 189, 207, 176, 242, 9, 66, 167, 122, 73, 10, 123, 39, 169, 19, 60, 103, 43, 164, - 118, 82, 94, 190, 127, 214, 40, 39, 73, 4, 49, 45, 32, 6, 144, 193, 234, 226, 255, 169, 98, - 233, 235, 134, 35, 35, 19, 131, 173, 15, 201, 217, 186, 130, 0, 141, 35, 195, 40, 10, 100, 18, - 7, 101, 159, 32, 2, 81, 151, 245, 177, 252, 226, 204, 173, 85, 24, 4, 95, 205, 23, 25, 251, 17, - 156, 214, 90, 28, 206, 86, 238, 192, 134, 49, 32, 50, 220, 6, 32, 1, 244, 205, 177, 90, 120, - 13, 60, 46, 86, 37, 234, 225, 106, 184, 139, 212, 169, 168, 244, 158, 52, 14, 135, 165, 147, - 70, 141, 255, 230, 132, 71, 32, 5, 82, 227, 139, 2, 40, 141, 165, 126, 161, 195, 112, 160, 172, - 14, 82, 222, 80, 169, 222, 77, 78, 246, 49, 169, 210, 143, 72, 95, 111, 245, 232, 32, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 7, 255, 255, 255, 254, 239, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 225, 32, 0, 85, 163, 31, 56, - 23, 227, 210, 35, 188, 95, 188, 220, 211, 243, 28, 54, 224, 187, 98, 102, 204, 33, 75, 193, - 122, 112, 91, 160, 41, 141, 89, 32, 4, 82, 203, 137, 115, 201, 150, 191, 166, 99, 222, 69, 222, - 149, 93, 212, 145, 31, 93, 65, 137, 126, 195, 126, 14, 129, 233, 26, 176, 49, 82, 127, 32, 4, - 82, 203, 137, 115, 201, 150, 191, 166, 99, 222, 69, 222, 149, 93, 212, 145, 31, 93, 65, 137, - 126, 195, 126, 14, 129, 233, 26, 176, 49, 82, 127, 32, 4, 82, 203, 137, 115, 201, 150, 191, - 166, 99, 222, 69, 222, 149, 93, 212, 145, 31, 93, 65, 137, 126, 195, 126, 14, 129, 233, 26, - 176, 49, 82, 127, 32, 1, 233, 68, 16, 26, 231, 26, 13, 224, 136, 35, 186, 24, 94, 164, 6, 24, - 215, 201, 121, 43, 164, 110, 63, 246, 152, 162, 110, 47, 24, 96, 170, 32, 3, 68, 254, 241, 184, - 31, 136, 240, 123, 184, 28, 56, 127, 116, 64, 6, 24, 157, 254, 225, 103, 224, 242, 60, 247, - 114, 65, 92, 85, 90, 123, 96, 32, 1, 10, 116, 233, 164, 250, 215, 87, 154, 28, 170, 97, 52, - 177, 105, 39, 86, 87, 202, 11, 143, 8, 136, 89, 112, 142, 108, 124, 64, 80, 51, 114, 32, 4, 21, - 88, 73, 189, 248, 220, 154, 103, 98, 52, 113, 214, 220, 147, 30, 108, 56, 18, 71, 125, 178, - 247, 106, 67, 91, 72, 195, 182, 228, 234, 65, 32, 3, 116, 200, 211, 20, 250, 150, 46, 138, 158, - 89, 97, 125, 50, 0, 184, 211, 5, 226, 38, 227, 131, 150, 173, 187, 92, 236, 2, 129, 165, 162, - 90, 32, 7, 246, 141, 58, 113, 220, 125, 16, 230, 82, 174, 150, 52, 27, 174, 148, 207, 155, 224, - 31, 47, 161, 188, 93, 245, 241, 130, 244, 30, 255, 124, 38, 32, 0, 135, 49, 230, 77, 253, 147, - 32, 220, 149, 28, 235, 161, 217, 174, 36, 68, 19, 159, 36, 83, 233, 51, 51, 186, 156, 127, 58, - 125, 30, 96, 122, 32, 7, 240, 8, 218, 58, 141, 142, 100, 113, 185, 80, 234, 52, 191, 204, 177, - 223, 215, 24, 78, 11, 179, 213, 100, 59, 147, 142, 164, 74, 151, 202, 69, 32, 1, 140, 105, 137, - 196, 179, 164, 211, 17, 24, 142, 88, 14, 86, 92, 225, 103, 24, 147, 40, 187, 235, 183, 55, 67, - 206, 227, 76, 204, 85, 184, 0, 32, 1, 135, 21, 139, 177, 98, 238, 207, 121, 193, 232, 92, 193, - 84, 9, 31, 216, 230, 39, 94, 172, 170, 159, 131, 182, 200, 138, 149, 14, 209, 206, 112, 32, 7, - 11, 30, 72, 239, 66, 212, 25, 127, 66, 185, 63, 122, 54, 102, 90, 179, 208, 114, 222, 205, 233, - 100, 158, 102, 46, 172, 22, 211, 50, 169, 25, 32, 5, 248, 84, 239, 52, 205, 176, 109, 244, 251, - 122, 75, 246, 35, 127, 128, 70, 49, 32, 115, 224, 197, 164, 76, 145, 73, 103, 249, 203, 3, 8, - 34, 32, 3, 182, 251, 2, 76, 2, 142, 40, 178, 93, 156, 100, 212, 170, 206, 213, 16, 219, 191, - 26, 30, 42, 165, 137, 226, 93, 53, 48, 171, 66, 68, 90, 32, 2, 86, 24, 111, 255, 37, 44, 8, 32, - 247, 101, 8, 1, 159, 181, 86, 5, 193, 11, 78, 116, 183, 128, 190, 11, 37, 228, 66, 246, 42, 97, - 110, 32, 4, 117, 243, 32, 94, 173, 84, 240, 137, 39, 233, 131, 234, 166, 202, 0, 236, 27, 207, - 132, 222, 66, 210, 98, 108, 171, 189, 246, 230, 47, 41, 26, 32, 1, 199, 163, 213, 238, 169, - 173, 178, 245, 231, 214, 11, 255, 224, 62, 111, 59, 172, 254, 158, 85, 74, 156, 10, 152, 165, - 56, 235, 116, 4, 108, 183, 32, 2, 170, 60, 84, 163, 133, 239, 248, 198, 183, 45, 151, 159, 73, - 224, 53, 124, 40, 72, 25, 104, 121, 11, 35, 168, 248, 70, 79, 138, 210, 80, 221, 32, 1, 40, 99, - 5, 136, 12, 170, 142, 106, 37, 14, 66, 49, 32, 54, 247, 127, 114, 170, 81, 249, 107, 55, 134, - 56, 187, 193, 158, 240, 253, 108, 80, 32, 5, 182, 30, 113, 205, 238, 106, 8, 90, 89, 34, 99, - 100, 150, 116, 249, 10, 180, 155, 11, 70, 101, 71, 184, 180, 231, 244, 181, 56, 64, 98, 130, - 59, 2, 81, 40, 194, 94, 50, 95, 48, 102, 131, 97, 175, 28, 49, 71, 186, 139, 175, 98, 168, 189, - 34, 246, 11, 62, 140, 164, 7, 236, 183, 220, 165, 23, 2, 32, 3, 59, 152, 143, 8, 230, 240, 130, - 56, 157, 110, 161, 54, 201, 38, 88, 116, 51, 223, 114, 113, 15, 169, 45, 163, 3, 70, 102, 109, - 19, 244, 104, 32, 0, 186, 60, 10, 233, 92, 232, 39, 29, 239, 122, 223, 0, 178, 158, 152, 250, - 205, 162, 150, 109, 186, 214, 94, 94, 177, 99, 135, 250, 5, 221, 183, 5, 191, 197, 255, 113, - 37, 76, 111, 0, 114, 147, 242, 154, 7, 31, 117, 190, 38, 136, 123, 37, 94, 212, 249, 107, 104, - 80, 4, 117, 47, 28, 126, 105, 100, 93, 30, 7, 47, 90, 129, 239, 158, 228, 34, 172, 127, 112, - 154, 50, 12, 80, 235, 240, 221, 100, 64, 218, 90, 178, 60, 166, 125, 246, 131, 68, 196, 7, 41, - 61, 53, 191, 99, 192, 168, 51, 141, 240, 195, 73, 136, 178, 77, 77, 171, 230, 34, 95, 63, 72, - 43, 244, 57, 163, 39, 196, 98, 156, 57, 136, 29, 175, 0, 243, 46, 77, 13, 125, 6, 114, 48, 71, - 249, 99, 8, 128, 225, 34, 110, 147, 55, 27, 63, 175, 194, 217, 227, 77, 218, 94, 36, 156, 0, - 179, 231, 72, 31, 255, 38, 212, 167, 10, 174, 191, 110, 250, 162, 207, 161, 168, 79, 19, 104, - 168, 119, 188, 151, 153, 175, 9, 106, 34, 32, 7, 89, 44, 91, 159, 254, 36, 38, 170, 34, 219, - 45, 217, 23, 164, 181, 224, 3, 112, 229, 190, 172, 251, 223, 99, 32, 86, 157, 216, 159, 150, - 134, 3, 5, 6, 246, 179, 126, 106, 191, 68, 175, 91, 52, 134, 173, 220, 51, 251, 208, 40, 255, - 118, 102, 190, 251, 93, 123, 255, 212, 245, 224, 113, 116, 137, 206, 87, 57, 244, 148, 152, 0, - 128, 157, 16, 56, 116, 99, 227, 198, 250, 122, 186, 236, 42, 50, 76, 9, 83, 241, 89, 4, 230, - 27, 247, 214, 211, 214, 51, 101, 38, 74, 72, 251, 114, 60, 34, 69, 106, 109, 151, 42, 19, 129, - 17, 81, 158, 13, 73, 210, 188, 86, 240, 151, 220, 230, 52, 216, 38, 80, 103, 198, 152, 20, 115, - 160, 242, 252, 109, 20, 133, 222, 45, 134, 88, 23, 53, 141, 242, 248, 15, 11, 233, 149, 220, 8, - 24, 184, 75, 145, 67, 83, 65, 38, 70, 80, 71, 140, 74, 31, 138, 79, 5, 128, 132, 58, 43, 187, - 35, 22, 21, 18, 103, 216, 32, 162, 130, 102, 175, 17, 149, 195, 87, 73, 219, 140, 227, 135, - 197, 119, 17, 126, 237, 56, 57, 61, 0, 204, 10, 66, 81, 3, 129, 39, 95, 45, 65, 40, 41, 56, 45, - 134, 5, 204, 210, 97, 78, 5, 38, 124, 9, 101, 142, 27, 84, 214, 74, 16, 193, 162, 40, 79, 83, - 118, 130, 252, 144, 216, 117, 20, 36, 197, 120, 236, 91, 6, 122, 117, 5, 112, 130, 41, 45, 144, - 152, 96, 9, 196, 129, 48, 16, 255, 225, 194, 146, 230, 3, 53, 10, 11, 140, 129, 168, 180, 93, - 205, 17, 231, 9, 178, 140, 111, 27, 159, 166, 190, 249, 104, 99, 61, 107, 11, 219, 187, 68, - 171, 121, 0, 216, 199, 162, 138, 56, 29, 97, 137, 103, 186, 71, 26, 99, 115, 20, 70, 113, 12, - 29, 203, 98, 47, 50, 42, 188, 136, 157, 159, 108, 58, 187, 27, 127, 128, 169, 115, 229, 0, 246, - 172, 193, 39, 151, 134, 244, 58, 180, 120, 43, 49, 21, 2, 128, 38, 87, 184, 224, 109, 146, 99, - 207, 186, 154, 49, 150, 19, 204, 201, 19, 234, 99, 213, 91, 151, 9, 196, 58, 87, 229, 152, 4, - 4, 126, 143, 216, 213, 112, 139, 15, 201, 95, 2, 36, 217, 63, 3, 105, 156, 95, 192, 51, 127, - 107, 106, 121, 210, 131, 78, 183, 183, 69, 25, 120, 44, 193, 12, 209, 45, 134, 135, 222, 241, - 166, 46, 114, 171, 24, 250, 218, 189, 180, 56, 88, 31, 14, 10, 88, 91, 149, 46, 96, 221, 211, - 22, 124, 81, 167, 63, 169, 248, 220, 97, 31, 195, 229, 74, 177, 27, 61, 77, 171, 136, 91, 82, - 220, 194, 82, 248, 99, 188, 73, 122, 16, 71, 237, 134, 1, 196, 199, 25, 78, 137, 117, 178, 73, - 206, 207, 21, 100, 255, 225, 230, 110, 174, 195, 238, 33, 12, 156, 193, 51, 0, 240, 58, 209, - 103, 211, 116, 115, 3, 170, 100, 105, 36, 129, 157, 209, 253, 124, 53, 241, 6, 182, 23, 7, 159, - 88, 62, 158, 115, 188, 253, 2, 170, 17, 70, 168, 52, 61, 68, 51, 253, 196, 42, 0, 254, 183, - 240, 250, 12, 238, 185, 121, 26, 184, 50, 44, 34, 3, 2, 220, 217, 35, 28, 228, 108, 234, 188, - 173, 162, 148, 6, 20, 215, 109, 161, 59, 133, 175, 155, 138, 223, 67, 58, 208, 208, 57, 184, - 255, 208, 223, 253, 96, 77, 82, 94, 162, 149, 202, 120, 84, 168, 8, 120, 5, 21, 2, 228, 224, - 251, 183, 51, 241, 205, 70, 71, 174, 39, 70, 44, 98, 213, 82, 247, 7, 238, 179, 81, 161, 63, - 253, 211, 240, 78, 26, 76, 138, 88, 174, 238, 69, 131, 238, 10, 18, 9, 29, 216, 100, 199, 207, - 12, 176, 207, 8, 112, 14, 218, 7, 227, 62, 90, 189, 46, 251, 64, 37, 198, 110, 193, 8, 5, 32, - 2, 53, 177, 181, 73, 30, 205, 173, 220, 83, 85, 163, 122, 76, 72, 209, 174, 204, 185, 68, 148, - 87, 57, 211, 21, 124, 77, 1, 138, 67, 232, 204, 32, 5, 190, 49, 41, 170, 42, 123, 189, 134, 59, - 109, 96, 132, 2, 113, 248, 182, 19, 95, 37, 38, 246, 165, 169, 167, 77, 234, 132, 114, 252, - 193, 202, 32, 4, 99, 225, 118, 96, 244, 206, 204, 17, 221, 132, 21, 229, 37, 141, 247, 211, 4, - 68, 142, 191, 195, 88, 152, 220, 88, 76, 4, 197, 177, 12, 214, 32, 5, 38, 255, 173, 131, 70, - 110, 116, 26, 128, 12, 98, 202, 124, 252, 80, 65, 8, 229, 49, 246, 78, 241, 67, 60, 23, 64, - 185, 65, 39, 206, 81, 32, 4, 25, 69, 22, 53, 127, 102, 201, 107, 148, 46, 230, 100, 85, 108, - 147, 141, 9, 174, 163, 116, 96, 182, 151, 135, 10, 113, 114, 236, 245, 181, 238, 5, 6, 35, 206, - 103, 148, 205, 117, 76, 61, 12, 48, 23, 5, 242, 56, 0, 215, 228, 225, 136, 53, 59, 169, 81, 8, - 40, 155, 103, 197, 99, 235, 16, 209, 178, 57, 5, 119, 238, 168, 13, 118, 11, 238, 238, 224, - 190, 249, 62, 193, 98, 60, 71, 89, 220, 228, 201, 68, 103, 220, 150, 109, 187, 47, 224, 77, - 196, 7, 66, 181, 5, 42, 122, 97, 187, 255, 117, 22, 153, 101, 77, 11, 139, 70, 191, 8, 251, 29, - 151, 211, 11, 0, 186, 240, 214, 153, 111, 90, 88, 71, 125, 201, 195, 48, 92, 86, 191, 88, 229, - 232, 219, 36, 59, 39, 114, 20, 132, 73, 45, 70, 209, 110, 10, 29, 36, 145, 114, 251, 67, 187, - 198, 56, 212, 81, 250, 16, 79, 103, 92, 154, 98, 38, 219, 99, 170, 32, 195, 125, 84, 232, 191, - 119, 194, 156, 205, 244, 79, 241, 78, 89, 141, 126, 26, 205, 114, 67, 180, 106, 213, 33, 106, - 197, 243, 69, 119, 34, 222, 128, 69, 79, 102, 182, 187, 255, 109, 118, 158, 221, 63, 140, 221, - 181, 100, 171, 5, 133, 145, 42, 78, 125, 28, 43, 70, 42, 186, 177, 41, 99, 205, 160, 88, 110, - 62, 192, 104, 20, 151, 182, 248, 160, 121, 133, 52, 4, 160, 118, 246, 116, 92, 46, 138, 126, - 248, 114, 8, 31, 247, 96, 127, 173, 15, 249, 167, 220, 38, 136, 204, 21, 6, 121, 161, 160, 170, - 182, 226, 186, 169, 22, 163, 69, 162, 168, 54, 117, 238, 54, 206, 179, 27, 90, 253, 221, 89, - 105, 212, 143, 173, 228, 71, 158, 186, 45, 166, 56, 3, 126, 48, 100, 210, 124, 189, 23, 14, - 128, 47, 97, 219, 227, 61, 143, 51, 202, 139, 93, 234, 28, 241, 172, 82, 17, 137, 229, 105, - 116, 130, 254, 8, 172, 3, 64, 131, 41, 219, 198, 75, 234, 228, 214, 85, 172, 171, 128, 249, - 187, 230, 112, 23, 37, 20, 157, 7, 27, 41, 84, 224, 191, 3, 23, 75, 240, 27, 100, 70, 210, 195, - 4, 191, 241, 3, 182, 94, 188, 246, 181, 59, 105, 212, 62, 227, 163, 12, 135, 24, 51, 112, 25, - 199, 64, 13, 77, 147, 139, 80, 0, 92, 130, 148, 26, 17, 247, 231, 121, 216, 41, 3, 10, 252, - 187, 119, 114, 164, 108, 234, 49, 175, 234, 231, 41, 45, 30, 39, 1, 190, 145, 201, 15, 8, 22, - 55, 53, 139, 155, 53, 18, 168, 188, 29, 162, 181, 3, 207, 53, 159, 91, 89, 96, 109, 77, 124, - 29, 240, 31, 46, 218, 129, 77, 115, 141, 91, 102, 234, 124, 198, 244, 147, 73, 94, 30, 79, 130, - 91, 218, 2, 130, 225, 38, 52, 218, 233, 69, 30, 157, 212, 66, 234, 171, 133, 143, 124, 183, 11, - 235, 31, 177, 3, 204, 32, 166, 100, 39, 193, 38, 248, 52, 4, 129, 217, 9, 220, 182, 49, 251, - 39, 107, 211, 0, 245, 201, 107, 242, 143, 71, 121, 51, 249, 165, 46, 23, 128, 11, 61, 175, 105, - 39, 37, 155, 204, 121, 212, 38, 230, 164, 115, 57, 156, 245, 171, 246, 232, 129, 6, 254, 141, - 215, 29, 141, 58, 47, 66, 43, 4, 254, 39, 139, 195, 145, 92, 32, 238, 239, 240, 50, 213, 218, - 68, 133, 46, 151, 110, 52, 2, 169, 49, 135, 165, 218, 89, 49, 237, 210, 243, 2, 14, 84, 56, 39, - 228, 229, 73, 77, 195, 22, 26, 100, 255, 181, 102, 59, 30, 163, 16, 139, 27, 85, 234, 67, 146, - 230, 156, 100, 127, 246, 127, 171, 148, 223, 151, 248, 153, 169, 41, 238, 236, 5, 236, 194, - 181, 156, 241, 35, 232, 9, 159, 4, 166, 114, 64, 17, 238, 81, 45, 149, 246, 230, 19, 206, 5, - 32, 5, 11, 127, 120, 224, 216, 11, 231, 157, 196, 26, 184, 246, 76, 29, 50, 215, 189, 157, 230, - 11, 54, 160, 49, 108, 231, 52, 99, 92, 194, 102, 207, 32, 1, 214, 182, 1, 138, 8, 244, 88, 230, - 8, 201, 161, 57, 243, 99, 19, 79, 63, 229, 54, 218, 119, 91, 204, 48, 115, 27, 238, 119, 64, - 172, 118, 32, 4, 207, 122, 49, 125, 13, 117, 161, 85, 171, 186, 253, 30, 163, 122, 5, 237, 245, - 144, 169, 104, 212, 7, 140, 51, 160, 138, 148, 16, 34, 249, 195, 32, 0, 71, 172, 162, 180, 200, - 209, 207, 156, 53, 1, 127, 200, 71, 88, 190, 236, 124, 110, 38, 123, 155, 251, 231, 114, 116, - 156, 53, 89, 208, 61, 151, 32, 4, 113, 153, 32, 192, 100, 22, 16, 201, 77, 239, 20, 86, 1, 235, - 53, 150, 98, 235, 96, 18, 233, 179, 164, 25, 193, 63, 21, 122, 3, 248, 105, 5, 6, 164, 12, 33, - 111, 122, 156, 1, 168, 199, 62, 164, 37, 109, 13, 28, 3, 127, 52, 192, 217, 20, 217, 54, 30, - 87, 115, 28, 245, 103, 74, 204, 0, 33, 202, 205, 4, 20, 17, 50, 16, 132, 83, 34, 132, 92, 235, - 201, 102, 52, 188, 200, 76, 18, 228, 92, 83, 175, 155, 103, 228, 215, 118, 159, 182, 42, 16, - 72, 162, 176, 102, 176, 177, 203, 127, 144, 107, 144, 163, 132, 11, 78, 241, 164, 167, 58, 193, - 114, 216, 171, 102, 38, 70, 53, 126, 61, 191, 34, 147, 34, 168, 7, 171, 42, 57, 249, 70, 123, - 175, 213, 73, 149, 142, 114, 23, 172, 114, 124, 202, 224, 28, 255, 135, 221, 159, 60, 24, 20, - 74, 200, 160, 22, 80, 246, 8, 128, 255, 119, 25, 125, 123, 242, 124, 209, 136, 143, 121, 34, - 111, 211, 122, 132, 110, 158, 250, 151, 69, 95, 234, 251, 130, 26, 205, 114, 67, 180, 106, 213, - 33, 106, 197, 243, 69, 119, 34, 222, 128, 69, 79, 102, 182, 187, 255, 109, 118, 158, 221, 63, - 140, 221, 181, 100, 171, 5, 76, 4, 146, 12, 139, 155, 4, 69, 46, 236, 79, 234, 143, 225, 193, - 76, 161, 84, 99, 142, 60, 88, 70, 75, 192, 217, 64, 11, 133, 46, 61, 183, 94, 146, 82, 29, 91, - 253, 170, 49, 236, 176, 134, 51, 185, 95, 198, 253, 19, 65, 164, 204, 219, 223, 36, 211, 74, - 208, 80, 100, 57, 142, 168, 132, 37, 147, 49, 205, 88, 172, 2, 224, 153, 28, 130, 48, 63, 67, - 23, 141, 110, 169, 137, 140, 14, 158, 178, 115, 42, 63, 15, 138, 144, 192, 134, 183, 2, 97, - 142, 39, 229, 55, 34, 94, 78, 5, 218, 84, 0, 30, 78, 76, 82, 4, 220, 16, 244, 123, 162, 2, 206, - 104, 149, 68, 211, 41, 53, 120, 198, 75, 234, 228, 214, 85, 172, 171, 128, 249, 187, 230, 112, - 23, 37, 20, 157, 7, 27, 41, 84, 224, 191, 3, 23, 75, 240, 27, 100, 70, 210, 195, 4, 36, 147, - 74, 215, 10, 150, 175, 201, 114, 187, 212, 216, 113, 108, 70, 126, 123, 34, 249, 1, 16, 138, - 44, 152, 22, 64, 197, 6, 214, 137, 190, 124, 209, 146, 155, 107, 173, 13, 115, 125, 79, 120, - 64, 145, 109, 4, 128, 230, 136, 148, 180, 64, 244, 246, 189, 144, 211, 133, 148, 22, 165, 229, - 189, 148, 245, 16, 104, 133, 160, 196, 74, 85, 185, 148, 61, 92, 177, 127, 14, 181, 231, 188, - 46, 27, 197, 25, 218, 197, 52, 57, 15, 211, 31, 26, 193, 124, 198, 244, 147, 73, 94, 30, 79, - 130, 91, 218, 2, 130, 225, 38, 52, 218, 233, 69, 30, 157, 212, 66, 234, 171, 133, 143, 124, - 183, 11, 235, 31, 177, 3, 181, 87, 26, 195, 234, 251, 110, 37, 94, 116, 176, 226, 137, 38, 150, - 183, 154, 99, 204, 62, 251, 0, 160, 251, 54, 167, 246, 16, 125, 152, 175, 87, 96, 226, 24, 189, - 180, 160, 122, 77, 21, 164, 175, 149, 249, 178, 201, 78, 33, 211, 7, 235, 1, 46, 34, 226, 21, - 209, 136, 255, 205, 21, 88, 139, 43, 4, 254, 39, 139, 195, 145, 92, 32, 238, 239, 240, 50, 213, - 218, 68, 133, 46, 151, 110, 52, 2, 169, 49, 135, 165, 218, 89, 49, 237, 210, 243, 2, 22, 16, - 32, 133, 38, 144, 148, 13, 159, 247, 18, 246, 110, 7, 144, 92, 69, 243, 171, 15, 68, 175, 124, - 39, 1, 27, 129, 52, 118, 71, 249, 245, 148, 223, 151, 248, 153, 169, 41, 238, 236, 5, 236, 194, - 181, 156, 241, 35, 232, 9, 159, 4, 166, 114, 64, 17, 238, 81, 45, 149, 246, 230, 19, 206, 5, - 32, 0, 229, 232, 96, 40, 27, 42, 229, 74, 187, 121, 137, 94, 87, 197, 134, 9, 128, 187, 209, - 125, 112, 130, 153, 34, 103, 150, 223, 78, 208, 76, 194, 32, 1, 100, 26, 54, 125, 116, 61, 194, - 159, 148, 251, 27, 155, 109, 210, 52, 127, 174, 154, 134, 79, 0, 141, 136, 16, 13, 211, 200, - 65, 58, 146, 239, 32, 7, 6, 136, 117, 146, 55, 105, 142, 209, 136, 219, 203, 115, 223, 180, - 210, 28, 11, 196, 55, 79, 90, 201, 103, 72, 12, 59, 45, 112, 201, 24, 65, 32, 0, 7, 94, 141, - 111, 191, 0, 195, 202, 200, 119, 6, 132, 212, 134, 216, 57, 227, 2, 221, 200, 201, 178, 143, - 58, 84, 219, 80, 220, 2, 253, 92, 32, 1, 50, 62, 152, 210, 206, 241, 144, 59, 40, 86, 111, 87, - 191, 90, 95, 229, 37, 203, 207, 141, 0, 20, 107, 249, 224, 98, 219, 39, 215, 89, 68, 3, 7, 71, - 144, 201, 240, 215, 250, 18, 240, 139, 173, 118, 113, 1, 120, 216, 213, 149, 8, 143, 89, 203, - 46, 33, 53, 71, 53, 253, 178, 194, 46, 59, 100, 171, 107, 164, 145, 127, 127, 217, 45, 10, 226, - 211, 248, 68, 149, 90, 192, 188, 192, 30, 254, 73, 35, 168, 255, 180, 188, 48, 68, 197, 148, - 222, 213, 42, 119, 202, 24, 60, 23, 71, 111, 65, 143, 210, 93, 54, 41, 77, 47, 122, 249, 201, - 154, 44, 97, 221, 116, 227, 181, 225, 50, 142, 87, 197, 106, 67, 105, 202, 95, 192, 177, 11, - 247, 91, 10, 64, 41, 240, 160, 50, 16, 165, 50, 96, 148, 30, 52, 10, 84, 26, 209, 100, 142, 24, - 51, 60, 35, 69, 6, 89, 219, 68, 130, 201, 173, 86, 12, 163, 244, 36, 211, 115, 211, 9, 223, - 146, 68, 41, 67, 173, 118, 97, 81, 9, 162, 13, 100, 154, 99, 129, 111, 221, 39, 86, 255, 239, - 138, 10, 47, 174, 101, 145, 166, 252, 152, 243, 80, 232, 77, 7, 203, 91, 247, 4, 116, 31, 134, - 174, 248, 93, 33, 95, 169, 207, 128, 27, 89, 1, 160, 211, 197, 106, 105, 8, 18, 198, 172, 47, - 142, 177, 111, 50, 53, 251, 44, 163, 208, 234, 221, 23, 2, 131, 243, 7, 71, 144, 201, 240, 215, - 250, 18, 240, 139, 173, 118, 113, 1, 120, 216, 213, 149, 8, 143, 89, 203, 46, 33, 53, 71, 53, - 253, 178, 194, 46, 59, 100, 171, 107, 164, 145, 127, 127, 217, 45, 10, 226, 211, 248, 68, 149, - 90, 192, 188, 192, 30, 254, 73, 35, 168, 255, 180, 188, 48, 68, 197, 148, 222, 213, 42, 119, - 202, 24, 60, 23, 71, 111, 65, 143, 210, 93, 54, 41, 77, 47, 122, 249, 201, 154, 44, 97, 221, - 116, 227, 181, 225, 50, 142, 87, 197, 106, 67, 105, 202, 95, 192, 177, 11, 247, 91, 10, 64, 41, - 240, 160, 50, 16, 165, 50, 96, 148, 30, 52, 10, 84, 26, 209, 100, 142, 24, 51, 60, 35, 69, 6, - 89, 219, 68, 130, 201, 173, 86, 12, 163, 244, 36, 211, 115, 211, 9, 223, 146, 68, 41, 67, 173, - 118, 97, 81, 9, 162, 13, 100, 154, 99, 129, 111, 221, 39, 86, 255, 239, 138, 10, 47, 174, 101, - 145, 166, 252, 152, 243, 80, 232, 77, 7, 203, 91, 247, 4, 116, 31, 134, 174, 248, 93, 33, 95, - 169, 207, 128, 27, 89, 1, 160, 211, 197, 106, 105, 8, 18, 198, 172, 47, 142, 177, 111, 50, 53, - 251, 44, 163, 208, 234, 221, 23, 2, 131, 243, 2, 32, 0, 121, 56, 250, 191, 145, 92, 188, 216, - 190, 101, 171, 195, 113, 99, 119, 186, 15, 113, 37, 206, 159, 148, 1, 23, 162, 196, 34, 66, - 103, 235, 2, 32, 1, 185, 21, 77, 118, 124, 60, 175, 74, 130, 102, 105, 31, 124, 163, 66, 180, - 173, 28, 124, 14, 110, 11, 98, 167, 60, 140, 179, 22, 255, 254, 168, 2, 32, 7, 93, 221, 51, - 199, 202, 203, 104, 105, 110, 183, 155, 74, 106, 124, 166, 229, 248, 123, 245, 231, 137, 153, - 69, 29, 164, 232, 54, 185, 177, 144, 156, 32, 6, 92, 247, 229, 32, 239, 44, 49, 110, 136, 183, - 170, 109, 161, 234, 43, 34, 77, 148, 180, 29, 121, 194, 196, 241, 24, 8, 254, 84, 31, 188, 206, - 8, 194, 103, 122, 106, 133, 250, 174, 125, 151, 130, 221, 8, 187, 134, 62, 93, 238, 46, 68, 61, - 167, 238, 72, 165, 138, 70, 15, 221, 227, 108, 159, 211, 131, 70, 125, 230, 181, 220, 27, 253, - 58, 252, 147, 128, 189, 210, 74, 207, 212, 17, 72, 163, 85, 131, 170, 38, 103, 189, 141, 248, - 61, 249, 136, 57, 241, 119, 208, 181, 134, 105, 21, 33, 166, 131, 235, 219, 32, 129, 118, 34, - 232, 235, 114, 0, 195, 67, 28, 186, 223, 56, 179, 11, 237, 203, 61, 182, 16, 240, 189, 10, 233, - 240, 239, 118, 135, 208, 4, 191, 121, 46, 76, 28, 224, 7, 202, 70, 81, 20, 212, 158, 154, 216, - 34, 129, 208, 84, 111, 9, 55, 77, 55, 213, 97, 55, 55, 220, 12, 76, 40, 77, 61, 52, 184, 157, - 58, 168, 66, 193, 21, 82, 135, 102, 126, 82, 211, 245, 178, 95, 90, 192, 177, 115, 174, 223, - 201, 148, 203, 101, 124, 93, 251, 60, 92, 6, 129, 157, 253, 12, 39, 179, 125, 49, 33, 231, 78, - 160, 206, 9, 108, 129, 86, 213, 205, 155, 79, 131, 108, 160, 52, 154, 213, 1, 2, 193, 57, 70, - 160, 111, 191, 152, 93, 207, 46, 157, 48, 185, 149, 118, 242, 43, 120, 37, 73, 122, 229, 1, - 245, 56, 5, 205, 93, 162, 166, 145, 96, 161, 33, 161, 65, 184, 51, 169, 25, 255, 44, 212, 36, - 131, 40, 81, 24, 243, 77, 184, 160, 102, 8, 80, 73, 236, 40, 41, 138, 13, 203, 77, 220, 39, - 192, 112, 219, 4, 167, 70, 28, 67, 119, 81, 103, 37, 40, 147, 203, 205, 85, 240, 83, 155, 176, - 131, 70, 125, 230, 181, 220, 27, 253, 58, 252, 147, 128, 189, 210, 74, 207, 212, 17, 72, 163, - 85, 131, 170, 38, 103, 189, 141, 248, 61, 249, 136, 57, 241, 119, 208, 181, 134, 105, 21, 33, - 166, 131, 235, 219, 32, 129, 118, 34, 232, 235, 114, 0, 195, 67, 28, 186, 223, 56, 179, 11, - 237, 203, 61, 182, 16, 240, 189, 10, 233, 240, 239, 118, 135, 208, 4, 191, 121, 46, 76, 28, - 224, 7, 202, 70, 81, 20, 212, 158, 154, 216, 34, 129, 208, 84, 111, 9, 55, 77, 55, 213, 97, 55, - 55, 220, 12, 76, 40, 77, 61, 52, 184, 157, 58, 168, 66, 193, 21, 82, 135, 102, 126, 82, 211, - 245, 178, 95, 90, 192, 177, 115, 174, 223, 201, 148, 203, 101, 124, 93, 251, 60, 92, 6, 129, - 157, 253, 12, 39, 179, 125, 49, 33, 231, 78, 160, 206, 9, 108, 129, 86, 213, 205, 155, 79, 131, - 108, 160, 52, 154, 213, 1, 2, 193, 57, 70, 160, 111, 191, 152, 93, 207, 46, 157, 48, 185, 149, - 118, 242, 43, 120, 37, 73, 122, 229, 1, 245, 56, 5, 205, 93, 162, 166, 145, 96, 161, 33, 161, - 65, 184, 51, 169, 25, 255, 44, 212, 36, 131, 40, 81, 24, 243, 77, 184, 160, 102, 36, 32, 3, - 129, 119, 190, 233, 95, 78, 6, 164, 208, 157, 160, 250, 100, 42, 203, 176, 155, 49, 231, 195, - 75, 98, 177, 115, 153, 74, 226, 248, 25, 241, 7, 32, 6, 30, 171, 74, 37, 11, 19, 154, 170, 254, - 51, 117, 130, 110, 115, 62, 192, 170, 139, 56, 62, 57, 158, 94, 28, 100, 88, 173, 48, 170, 207, - 140, 32, 5, 20, 146, 220, 46, 138, 162, 114, 98, 139, 169, 186, 205, 89, 171, 101, 133, 249, - 107, 248, 175, 10, 75, 108, 59, 159, 233, 43, 80, 213, 109, 94, 32, 3, 98, 145, 109, 12, 196, - 173, 204, 125, 79, 154, 75, 3, 29, 114, 109, 4, 145, 157, 223, 188, 165, 15, 192, 123, 214, - 165, 253, 55, 68, 28, 81, 32, 2, 10, 123, 248, 147, 236, 105, 36, 203, 106, 196, 189, 79, 212, - 58, 99, 118, 26, 109, 22, 220, 58, 70, 105, 25, 56, 26, 154, 2, 136, 245, 131, 32, 7, 211, 194, - 187, 70, 236, 198, 225, 140, 232, 165, 89, 61, 51, 255, 74, 133, 166, 176, 129, 11, 21, 122, - 161, 83, 72, 148, 74, 11, 132, 45, 214, 32, 0, 55, 64, 185, 27, 30, 92, 171, 102, 124, 242, - 227, 150, 231, 16, 104, 44, 2, 124, 152, 92, 159, 52, 70, 171, 219, 107, 38, 84, 198, 8, 37, - 32, 4, 27, 160, 92, 141, 143, 46, 94, 51, 62, 121, 113, 203, 115, 136, 52, 22, 1, 62, 76, 46, - 79, 154, 35, 85, 237, 181, 147, 42, 99, 4, 19, 32, 3, 75, 39, 32, 29, 166, 11, 219, 98, 39, - 181, 83, 161, 195, 143, 239, 231, 232, 8, 88, 81, 117, 221, 8, 36, 251, 170, 187, 80, 31, 93, - 194, 32, 3, 6, 149, 89, 255, 239, 143, 122, 54, 188, 9, 228, 199, 26, 104, 189, 59, 237, 133, - 253, 67, 140, 226, 103, 143, 213, 180, 223, 107, 159, 236, 170, 32, 3, 60, 210, 185, 66, 121, - 78, 183, 213, 211, 116, 101, 54, 192, 162, 238, 230, 148, 228, 44, 51, 70, 109, 7, 123, 71, - 213, 240, 152, 54, 164, 65, 32, 3, 159, 58, 200, 43, 22, 119, 51, 45, 204, 247, 143, 15, 4, 98, - 94, 200, 132, 49, 204, 255, 169, 167, 158, 72, 20, 54, 106, 231, 84, 92, 52, 32, 1, 218, 176, - 67, 127, 66, 251, 233, 84, 65, 226, 188, 240, 237, 20, 202, 237, 113, 7, 46, 155, 214, 62, 226, - 28, 23, 237, 26, 102, 55, 39, 176, 32, 6, 232, 26, 234, 163, 156, 102, 112, 157, 20, 97, 94, - 108, 84, 24, 159, 81, 20, 93, 58, 189, 253, 163, 51, 224, 158, 57, 184, 122, 155, 142, 81, 32, - 4, 177, 100, 103, 40, 172, 167, 228, 151, 18, 169, 73, 242, 51, 216, 37, 133, 113, 151, 207, - 153, 76, 225, 144, 106, 83, 236, 205, 248, 59, 162, 225, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 6, 71, 147, 94, 188, 32, - 176, 254, 19, 157, 26, 137, 172, 32, 163, 155, 79, 52, 255, 175, 229, 18, 186, 113, 105, 132, - 104, 52, 163, 248, 142, 208, 32, 4, 166, 238, 8, 11, 43, 74, 210, 63, 25, 67, 189, 207, 187, - 245, 253, 52, 248, 231, 14, 189, 154, 43, 250, 35, 76, 37, 215, 135, 65, 227, 22, 32, 4, 47, - 103, 10, 197, 213, 252, 162, 42, 145, 131, 167, 96, 151, 25, 47, 48, 38, 129, 163, 167, 107, - 249, 172, 38, 253, 151, 177, 87, 200, 173, 28, 32, 7, 186, 189, 130, 192, 153, 251, 2, 33, 229, - 165, 127, 180, 249, 35, 117, 112, 33, 115, 145, 147, 172, 33, 142, 187, 170, 4, 139, 29, 224, - 160, 210, 32, 4, 28, 184, 49, 152, 3, 85, 40, 119, 139, 199, 84, 181, 196, 60, 206, 122, 105, - 218, 219, 126, 46, 144, 52, 99, 90, 200, 68, 230, 112, 50, 7, 32, 0, 143, 89, 58, 248, 81, 33, - 199, 61, 217, 53, 87, 115, 72, 77, 3, 61, 95, 207, 90, 227, 78, 127, 46, 65, 119, 75, 251, 158, - 31, 6, 8, 32, 0, 1, 96, 195, 251, 88, 10, 103, 180, 61, 142, 122, 134, 133, 249, 113, 231, 174, - 231, 255, 139, 209, 47, 182, 98, 238, 34, 83, 54, 254, 99, 49, 32, 1, 82, 59, 58, 227, 77, 153, - 24, 209, 88, 85, 186, 180, 254, 171, 109, 253, 16, 57, 88, 219, 90, 239, 17, 0, 17, 100, 240, - 220, 183, 85, 182, 32, 1, 142, 178, 105, 92, 163, 212, 56, 242, 59, 143, 191, 116, 0, 215, 124, - 174, 173, 137, 49, 254, 194, 89, 242, 69, 21, 189, 14, 89, 248, 245, 88, 32, 2, 54, 63, 177, - 227, 177, 184, 102, 42, 51, 209, 207, 67, 54, 99, 26, 65, 219, 56, 113, 205, 38, 44, 209, 138, - 155, 63, 110, 28, 200, 151, 241, 32, 7, 229, 236, 148, 234, 123, 72, 117, 113, 139, 172, 110, - 99, 178, 167, 122, 62, 13, 136, 204, 74, 10, 226, 91, 173, 138, 154, 97, 151, 123, 223, 206, - 32, 5, 85, 34, 196, 27, 77, 181, 221, 26, 73, 1, 22, 10, 80, 110, 66, 21, 49, 199, 67, 162, - 116, 49, 144, 44, 61, 99, 198, 139, 76, 135, 36, 32, 4, 200, 179, 24, 128, 240, 75, 3, 198, - 248, 102, 12, 18, 182, 96, 105, 231, 198, 74, 33, 224, 93, 145, 21, 175, 17, 1, 237, 91, 204, - 229, 171, 32, 4, 227, 19, 99, 106, 229, 101, 222, 183, 158, 106, 45, 38, 55, 145, 83, 24, 92, - 146, 26, 59, 11, 30, 30, 92, 238, 22, 85, 224, 224, 21, 141, 32, 5, 161, 95, 191, 179, 148, 84, - 11, 254, 155, 247, 34, 140, 107, 99, 2, 47, 150, 238, 214, 74, 231, 255, 38, 86, 141, 136, 194, - 251, 152, 182, 131, 32, 5, 102, 212, 36, 93, 231, 48, 242, 148, 77, 217, 10, 122, 125, 133, - 208, 97, 3, 54, 255, 252, 0, 28, 14, 96, 187, 107, 212, 242, 23, 182, 175, 32, 7, 155, 119, - 145, 237, 64, 119, 216, 95, 27, 96, 211, 100, 166, 152, 172, 113, 70, 11, 18, 181, 196, 177, - 34, 236, 37, 32, 167, 27, 170, 157, 230, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 254, 239, 253, 240, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 239, 255, 225, 36, 32, 3, 199, 206, 107, 71, 236, 106, 177, 255, 227, 253, 123, 135, - 103, 188, 215, 62, 209, 46, 59, 208, 236, 108, 98, 191, 187, 157, 98, 142, 102, 121, 68, 32, 6, - 79, 95, 173, 160, 177, 131, 243, 161, 131, 164, 120, 178, 230, 68, 12, 56, 5, 13, 48, 171, 116, - 183, 133, 250, 53, 60, 106, 41, 207, 159, 70, 32, 3, 133, 132, 119, 163, 155, 63, 179, 68, 227, - 9, 34, 105, 250, 219, 126, 152, 35, 54, 6, 188, 215, 173, 99, 99, 246, 139, 178, 182, 111, 81, - 89, 32, 3, 16, 73, 63, 92, 193, 214, 229, 171, 227, 122, 234, 245, 100, 209, 126, 146, 63, 98, - 124, 212, 85, 39, 132, 238, 183, 145, 147, 71, 220, 109, 4, 32, 3, 194, 163, 50, 173, 39, 36, - 9, 15, 158, 149, 55, 207, 227, 100, 8, 83, 61, 204, 168, 66, 179, 54, 162, 168, 108, 22, 76, - 96, 202, 181, 204, 32, 2, 89, 76, 2, 204, 217, 35, 122, 196, 176, 124, 127, 210, 89, 82, 251, - 217, 83, 3, 112, 210, 231, 167, 157, 230, 105, 113, 233, 134, 228, 23, 85, 32, 3, 30, 155, 129, - 254, 166, 255, 133, 144, 179, 238, 60, 171, 69, 71, 87, 43, 120, 24, 0, 133, 178, 36, 127, 188, - 104, 76, 223, 203, 230, 99, 170, 32, 1, 143, 77, 192, 255, 83, 127, 194, 200, 89, 247, 30, 85, - 162, 163, 171, 149, 188, 12, 0, 66, 217, 18, 63, 222, 52, 38, 111, 229, 243, 49, 213, 32, 2, - 172, 109, 220, 174, 129, 204, 2, 220, 164, 38, 94, 136, 55, 130, 146, 75, 17, 206, 218, 3, 102, - 105, 224, 101, 153, 229, 87, 246, 68, 221, 135, 32, 1, 149, 198, 58, 96, 9, 49, 126, 79, 110, - 13, 207, 32, 134, 103, 226, 155, 88, 36, 213, 112, 46, 32, 203, 202, 12, 4, 107, 213, 240, 153, - 108, 32, 6, 193, 52, 80, 237, 249, 242, 12, 225, 6, 202, 166, 240, 255, 170, 218, 37, 43, 77, - 92, 142, 72, 136, 146, 178, 206, 145, 59, 149, 98, 224, 13, 32, 3, 83, 150, 131, 170, 224, 26, - 20, 11, 16, 234, 249, 188, 157, 51, 86, 97, 143, 44, 30, 124, 95, 47, 52, 177, 91, 85, 243, - 131, 66, 78, 105, 32, 1, 149, 172, 10, 54, 235, 79, 163, 113, 233, 57, 53, 160, 204, 17, 63, - 219, 80, 112, 152, 37, 92, 157, 224, 143, 148, 148, 85, 62, 136, 248, 71, 32, 4, 109, 1, 100, - 72, 51, 43, 48, 196, 211, 101, 180, 191, 222, 79, 39, 113, 135, 136, 221, 171, 144, 253, 79, - 224, 238, 92, 172, 253, 188, 250, 126, 32, 0, 27, 71, 174, 82, 241, 161, 177, 90, 224, 221, - 169, 189, 85, 88, 80, 56, 247, 141, 72, 183, 194, 95, 104, 102, 247, 0, 118, 130, 41, 193, 219, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 32, 4, 82, 54, 7, 49, 101, 106, 214, 102, 1, 233, 244, 193, 93, 130, 32, 168, 188, 230, - 188, 102, 61, 93, 127, 170, 101, 59, 128, 142, 1, 166, 157, 32, 5, 22, 159, 20, 167, 73, 185, - 156, 152, 182, 115, 119, 33, 171, 4, 130, 136, 241, 249, 169, 27, 145, 189, 187, 225, 208, 142, - 201, 30, 217, 49, 142, 32, 1, 216, 131, 104, 255, 119, 205, 58, 40, 87, 24, 234, 123, 77, 230, - 124, 147, 18, 242, 223, 147, 224, 14, 78, 131, 214, 46, 209, 231, 96, 118, 128, 32, 6, 14, 2, - 93, 58, 182, 69, 1, 144, 4, 105, 104, 4, 165, 212, 174, 81, 110, 147, 28, 86, 3, 222, 22, 192, - 82, 65, 67, 142, 232, 202, 154, 32, 0, 29, 182, 99, 6, 235, 18, 171, 131, 144, 6, 40, 124, 61, - 43, 49, 232, 111, 44, 32, 9, 31, 137, 242, 110, 97, 17, 83, 106, 154, 215, 208, 32, 3, 235, - 152, 197, 209, 31, 116, 249, 67, 15, 152, 183, 253, 89, 66, 168, 244, 218, 238, 163, 71, 220, - 170, 229, 51, 105, 118, 51, 218, 30, 54, 126, 32, 3, 85, 95, 59, 189, 104, 31, 126, 237, 244, - 220, 58, 232, 85, 74, 3, 57, 252, 91, 195, 83, 196, 252, 25, 226, 26, 141, 71, 67, 177, 5, 6, - 32, 0, 46, 64, 74, 73, 217, 110, 9, 7, 230, 209, 80, 169, 79, 124, 10, 37, 62, 144, 81, 146, - 215, 48, 78, 42, 83, 60, 74, 132, 253, 137, 146, 32, 5, 0, 131, 147, 109, 164, 234, 81, 154, - 201, 228, 8, 110, 246, 226, 165, 245, 22, 162, 158, 87, 9, 197, 77, 179, 233, 77, 181, 211, - 242, 158, 42, 32, 6, 224, 18, 1, 92, 0, 105, 103, 2, 32, 249, 162, 231, 161, 253, 97, 76, 1, - 125, 180, 142, 51, 60, 18, 236, 206, 224, 84, 246, 57, 248, 19, 32, 7, 190, 69, 246, 70, 79, - 127, 166, 210, 157, 182, 194, 131, 128, 118, 120, 81, 24, 111, 209, 9, 32, 207, 178, 229, 124, - 201, 148, 246, 246, 142, 205, 32, 4, 134, 186, 120, 56, 3, 243, 134, 229, 174, 74, 246, 217, - 210, 192, 228, 1, 148, 39, 70, 28, 154, 56, 232, 132, 11, 232, 154, 249, 112, 55, 217, 32, 7, - 56, 41, 190, 58, 231, 12, 246, 237, 190, 195, 110, 213, 75, 31, 17, 222, 134, 100, 120, 71, 69, - 72, 1, 230, 15, 217, 66, 4, 248, 16, 124, 32, 5, 188, 38, 77, 159, 63, 83, 169, 219, 60, 152, - 18, 161, 242, 114, 61, 130, 47, 11, 179, 82, 207, 98, 10, 144, 216, 130, 239, 83, 193, 199, - 178, 32, 7, 132, 124, 61, 241, 128, 83, 243, 79, 248, 74, 43, 81, 202, 182, 233, 133, 100, 14, - 57, 111, 26, 126, 150, 64, 165, 234, 134, 181, 34, 55, 165, 32, 3, 31, 73, 229, 68, 144, 202, - 228, 21, 130, 252, 252, 27, 80, 25, 50, 89, 42, 169, 99, 161, 108, 162, 154, 112, 242, 72, 137, - 122, 241, 112, 17, 32, 4, 243, 143, 69, 72, 200, 7, 170, 13, 200, 59, 116, 20, 205, 217, 246, - 128, 202, 68, 44, 142, 204, 203, 42, 76, 164, 238, 72, 153, 122, 75, 246, 32, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, - 255, 255, 254, 239, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 225, 1, 8, 237, 179, 98, 88, 233, 51, 210, 6, - 167, 130, 93, 55, 232, 127, 156, 91, 76, 239, 68, 134, 208, 25, 99, 61, 106, 114, 100, 100, - 202, 115, 37, 44, 218, 2, 186, 144, 37, 166, 153, 158, 219, 68, 61, 12, 200, 233, 21, 123, 232, - 231, 149, 163, 253, 55, 215, 25, 161, 141, 13, 65, 220, 15, 139, 189, 37, 60, 56, 238, 45, 238, - 233, 34, 144, 42, 54, 124, 105, 102, 152, 94, 136, 247, 211, 162, 165, 228, 46, 138, 68, 134, - 151, 182, 34, 159, 199, 90, 226, 219, 154, 242, 175, 197, 229, 250, 42, 205, 231, 1, 122, 176, - 198, 108, 147, 169, 190, 77, 175, 107, 114, 43, 235, 227, 197, 214, 26, 158, 224, 83, 185, 9, - 104, 243, 92, 148, 83, 190, 60, 176, 106, 175, 140, 147, 73, 101, 237, 188, 108, 19, 65, 116, - 145, 149, 253, 252, 105, 5, 138, 211, 73, 79, 204, 232, 61, 172, 180, 83, 99, 114, 24, 173, - 181, 9, 249, 66, 244, 243, 28, 6, 22, 9, 93, 177, 36, 120, 20, 204, 68, 64, 7, 53, 234, 171, - 124, 38, 37, 149, 112, 6, 12, 208, 212, 253, 153, 162, 216, 88, 168, 5, 228, 76, 95, 190, 212, - 22, 65, 3, 76, 99, 63, 137, 25, 155, 214, 236, 74, 55, 153, 234, 37, 81, 232, 1, 225, 172, 216, - 197, 57, 78, 49, 214, 188, 52, 42, 124, 251, 8, 13, 109, 160, 212, 245, 228, 41, 239, 40, 109, - 8, 146, 194, 27, 204, 132, 238, 53, 16, 202, 207, 17, 239, 164, 33, 229, 252, 20, 224, 104, - 164, 17, 183, 14, 67, 59, 128, 223, 116, 189, 121, 132, 18, 218, 2, 186, 144, 37, 166, 153, - 158, 219, 68, 61, 12, 200, 233, 21, 123, 232, 231, 149, 163, 253, 55, 215, 25, 161, 141, 13, - 65, 220, 15, 139, 189, 37, 60, 56, 238, 45, 238, 233, 34, 144, 42, 54, 124, 105, 102, 152, 94, - 136, 247, 211, 162, 165, 228, 46, 138, 68, 134, 151, 182, 34, 159, 199, 90, 226, 219, 154, 242, - 175, 197, 229, 250, 42, 205, 231, 1, 122, 176, 198, 108, 147, 169, 190, 77, 175, 107, 114, 43, - 235, 227, 197, 214, 26, 158, 224, 83, 185, 9, 104, 243, 92, 148, 83, 190, 60, 176, 106, 175, - 140, 147, 73, 101, 237, 188, 108, 19, 65, 116, 145, 149, 253, 252, 105, 5, 138, 211, 73, 79, - 204, 232, 61, 172, 180, 83, 99, 114, 24, 173, 181, 9, 249, 66, 244, 243, 28, 6, 22, 9, 93, 177, - 36, 120, 20, 204, 68, 64, 7, 53, 234, 171, 124, 38, 37, 149, 112, 6, 12, 208, 212, 253, 153, - 162, 216, 88, 168, 5, 228, 76, 95, 190, 212, 22, 65, 3, 76, 99, 63, 137, 25, 155, 214, 236, 74, - 55, 153, 234, 37, 81, 232, 1, 225, 172, 216, 197, 57, 78, 49, 214, 188, 52, 42, 124, 251, 8, - 13, 109, 160, 212, 245, 228, 41, 239, 40, 109, 23, 32, 2, 17, 191, 13, 65, 119, 85, 249, 17, - 92, 237, 204, 127, 184, 15, 49, 197, 226, 130, 126, 99, 36, 96, 197, 179, 187, 31, 31, 233, - 160, 68, 241, 32, 7, 206, 4, 40, 55, 114, 159, 241, 252, 234, 135, 168, 67, 180, 39, 1, 141, - 115, 86, 91, 161, 177, 119, 16, 209, 235, 177, 203, 87, 86, 251, 228, 32, 7, 206, 4, 40, 55, - 114, 159, 241, 252, 234, 135, 168, 67, 180, 39, 1, 141, 115, 86, 91, 161, 177, 119, 16, 209, - 235, 177, 203, 87, 86, 251, 228, 32, 7, 206, 4, 40, 55, 114, 159, 241, 252, 234, 135, 168, 67, - 180, 39, 1, 141, 115, 86, 91, 161, 177, 119, 16, 209, 235, 177, 203, 87, 86, 251, 228, 32, 5, - 126, 4, 169, 71, 226, 140, 162, 112, 243, 69, 253, 126, 213, 128, 226, 16, 138, 133, 74, 70, - 108, 227, 47, 153, 174, 224, 203, 12, 147, 52, 200, 32, 6, 193, 153, 141, 245, 54, 105, 175, - 163, 190, 14, 56, 253, 228, 176, 47, 69, 123, 172, 229, 19, 43, 113, 9, 64, 97, 146, 143, 28, - 203, 68, 10, 32, 0, 122, 157, 210, 13, 110, 158, 52, 190, 198, 246, 219, 175, 7, 178, 97, 22, - 253, 39, 96, 202, 39, 176, 47, 88, 122, 181, 4, 80, 217, 224, 135, 32, 2, 1, 65, 165, 19, 156, - 3, 194, 188, 84, 56, 251, 199, 184, 63, 212, 35, 203, 230, 255, 53, 40, 165, 222, 102, 153, - 115, 131, 114, 111, 166, 151, 32, 3, 213, 7, 129, 95, 200, 126, 66, 11, 191, 185, 128, 148, 80, - 66, 169, 92, 172, 239, 52, 14, 53, 250, 103, 91, 190, 3, 234, 137, 149, 105, 144, 32, 3, 43, - 147, 169, 240, 19, 141, 49, 203, 199, 89, 254, 62, 221, 82, 120, 12, 34, 18, 249, 33, 53, 55, - 248, 38, 98, 227, 188, 150, 92, 244, 204, 32, 7, 27, 152, 244, 181, 72, 109, 103, 173, 57, 198, - 123, 161, 69, 99, 86, 52, 64, 81, 176, 204, 94, 127, 95, 69, 136, 164, 152, 230, 3, 174, 14, - 32, 3, 247, 63, 85, 225, 79, 59, 246, 5, 110, 6, 58, 2, 194, 174, 172, 211, 221, 136, 206, 6, - 136, 213, 91, 112, 25, 229, 153, 20, 36, 168, 27, 32, 6, 131, 91, 36, 183, 36, 123, 45, 244, - 20, 248, 176, 94, 105, 52, 114, 33, 67, 143, 103, 160, 49, 228, 190, 75, 52, 26, 237, 192, 77, - 15, 46, 32, 2, 168, 103, 36, 140, 83, 102, 213, 43, 88, 27, 226, 198, 236, 195, 184, 25, 176, - 119, 124, 140, 173, 36, 73, 154, 193, 159, 230, 137, 186, 29, 71, 32, 7, 168, 168, 94, 122, - 106, 150, 128, 222, 47, 144, 21, 246, 173, 13, 236, 165, 178, 44, 71, 216, 199, 138, 141, 122, - 226, 164, 156, 123, 246, 17, 134, 32, 5, 9, 164, 60, 239, 241, 202, 222, 129, 1, 170, 58, 6, - 68, 66, 5, 242, 35, 239, 58, 230, 242, 157, 55, 32, 42, 0, 5, 43, 3, 101, 213, 32, 4, 51, 23, - 189, 56, 46, 233, 132, 3, 173, 9, 115, 191, 198, 227, 211, 90, 195, 182, 222, 243, 230, 167, - 143, 52, 49, 35, 53, 200, 207, 120, 99, 32, 0, 251, 241, 177, 6, 220, 102, 123, 6, 27, 124, 19, - 183, 66, 27, 37, 6, 216, 64, 143, 188, 82, 19, 147, 145, 80, 221, 202, 191, 60, 91, 86, 32, 0, - 214, 134, 34, 147, 200, 13, 138, 217, 65, 115, 234, 191, 204, 190, 82, 70, 202, 191, 80, 101, - 118, 51, 178, 192, 62, 242, 200, 56, 54, 192, 9, 32, 1, 110, 27, 195, 98, 170, 43, 59, 217, - 232, 98, 32, 22, 139, 57, 70, 169, 63, 110, 250, 22, 236, 155, 154, 100, 47, 198, 140, 235, - 204, 111, 217, 32, 3, 75, 35, 91, 24, 169, 136, 139, 155, 133, 24, 28, 191, 73, 57, 143, 9, - 241, 206, 251, 36, 93, 85, 135, 152, 143, 37, 92, 177, 223, 15, 184, 32, 0, 250, 132, 115, 105, - 253, 239, 192, 45, 73, 230, 199, 246, 175, 224, 180, 183, 37, 138, 177, 98, 51, 90, 49, 103, - 207, 76, 68, 99, 22, 187, 176, 32, 3, 201, 205, 13, 7, 146, 33, 137, 199, 197, 4, 205, 247, 22, - 234, 67, 160, 44, 65, 218, 237, 87, 174, 145, 11, 246, 234, 123, 215, 163, 253, 153, 23, 32, 7, - 40, 186, 42, 229, 144, 128, 104, 28, 141, 143, 69, 147, 62, 158, 76, 84, 172, 75, 247, 6, 108, - 67, 166, 2, 173, 252, 132, 4, 108, 124, 8, 32, 7, 83, 140, 31, 122, 3, 69, 159, 7, 232, 129, - 164, 132, 12, 48, 240, 50, 12, 148, 235, 148, 110, 234, 156, 238, 71, 230, 119, 211, 1, 228, - 27, 32, 7, 83, 140, 31, 122, 3, 69, 159, 7, 232, 129, 164, 132, 12, 48, 240, 50, 12, 148, 235, - 148, 110, 234, 156, 238, 71, 230, 119, 211, 1, 228, 27, 32, 7, 83, 140, 31, 122, 3, 69, 159, 7, - 232, 129, 164, 132, 12, 48, 240, 50, 12, 148, 235, 148, 110, 234, 156, 238, 71, 230, 119, 211, - 1, 228, 27, 32, 6, 81, 4, 5, 187, 206, 59, 110, 65, 84, 150, 241, 236, 179, 248, 177, 175, 111, - 158, 196, 105, 92, 71, 203, 232, 52, 75, 138, 69, 207, 241, 248, 32, 2, 128, 65, 140, 233, 102, - 199, 198, 75, 33, 0, 137, 159, 117, 51, 62, 172, 159, 215, 245, 74, 173, 55, 140, 15, 213, 196, - 132, 85, 135, 141, 98, 32, 0, 79, 210, 136, 54, 105, 220, 119, 179, 48, 57, 215, 193, 250, 145, - 108, 224, 19, 203, 205, 248, 52, 89, 144, 152, 17, 12, 251, 207, 67, 78, 64, 32, 4, 68, 211, - 92, 201, 60, 140, 253, 162, 89, 86, 1, 183, 232, 242, 134, 180, 46, 79, 222, 180, 52, 206, 84, - 243, 126, 55, 22, 133, 20, 72, 199, 32, 6, 186, 118, 199, 147, 149, 206, 181, 154, 137, 217, - 96, 17, 196, 58, 155, 244, 155, 82, 24, 143, 113, 126, 35, 144, 132, 72, 183, 54, 130, 16, 139, - 32, 2, 82, 36, 138, 153, 216, 233, 108, 58, 21, 22, 112, 231, 100, 131, 225, 204, 114, 67, 87, - 249, 103, 22, 219, 175, 183, 229, 88, 61, 185, 173, 141, 32, 6, 50, 107, 206, 160, 16, 163, - 226, 125, 10, 148, 73, 7, 46, 253, 201, 6, 236, 13, 218, 23, 224, 219, 131, 165, 46, 231, 93, - 204, 232, 50, 131, 32, 0, 239, 92, 91, 87, 138, 39, 92, 122, 130, 163, 126, 38, 34, 40, 255, - 69, 139, 139, 45, 213, 190, 8, 87, 196, 235, 249, 168, 78, 37, 250, 199, 32, 5, 120, 113, 181, - 132, 210, 218, 53, 230, 246, 181, 76, 26, 15, 74, 72, 106, 31, 116, 173, 140, 91, 219, 183, 32, - 187, 142, 89, 110, 132, 88, 129, 32, 7, 155, 198, 105, 157, 249, 47, 37, 44, 97, 123, 71, 251, - 65, 204, 111, 111, 14, 173, 217, 223, 153, 105, 223, 201, 210, 231, 85, 189, 135, 196, 0, 32, - 6, 200, 219, 128, 22, 203, 43, 126, 142, 87, 15, 86, 37, 243, 106, 43, 56, 156, 131, 15, 81, - 72, 66, 124, 77, 59, 157, 7, 42, 60, 244, 124, 32, 6, 181, 126, 106, 82, 115, 69, 76, 107, 51, - 167, 68, 162, 210, 117, 215, 89, 58, 243, 130, 155, 21, 234, 183, 250, 129, 155, 85, 155, 108, - 151, 140, 32, 0, 166, 82, 192, 45, 78, 203, 142, 155, 201, 20, 171, 193, 107, 184, 156, 89, 2, - 19, 198, 85, 209, 81, 76, 180, 82, 156, 58, 224, 52, 205, 221, 32, 1, 196, 61, 126, 137, 240, - 148, 9, 9, 253, 171, 13, 92, 127, 29, 56, 205, 152, 45, 138, 62, 254, 193, 238, 205, 70, 57, - 121, 179, 242, 138, 251, 32, 4, 75, 100, 121, 255, 134, 223, 225, 177, 159, 210, 35, 241, 156, - 130, 95, 120, 173, 124, 47, 177, 97, 224, 57, 23, 25, 165, 108, 57, 1, 155, 35, 32, 7, 171, 44, - 251, 194, 49, 135, 254, 79, 91, 67, 109, 186, 188, 59, 243, 55, 145, 223, 165, 19, 66, 57, 205, - 129, 32, 175, 119, 209, 167, 220, 183, 32, 5, 212, 43, 29, 105, 249, 35, 186, 54, 219, 114, 24, - 170, 94, 3, 224, 223, 145, 70, 62, 32, 101, 203, 15, 120, 138, 130, 73, 207, 197, 29, 83, 32, - 3, 31, 248, 59, 171, 202, 243, 209, 210, 123, 161, 240, 53, 28, 192, 168, 254, 69, 157, 162, - 74, 58, 196, 12, 171, 253, 192, 65, 67, 179, 176, 37, 32, 2, 180, 24, 98, 175, 164, 83, 76, - 108, 48, 87, 254, 102, 209, 34, 235, 189, 202, 219, 31, 1, 250, 240, 170, 135, 21, 82, 2, 124, - 240, 29, 223, 7, 192, 156, 247, 205, 120, 212, 60, 245, 215, 170, 209, 61, 234, 57, 186, 21, 3, - 201, 140, 27, 79, 94, 235, 24, 172, 136, 92, 51, 137, 84, 9, 162, 91, 13, 118, 116, 9, 129, 94, - 37, 189, 55, 94, 221, 169, 97, 203, 178, 72, 137, 43, 10, 37, 137, 39, 19, 214, 251, 44, 76, - 119, 4, 28, 219, 57, 31, 20, 137, 195, 106, 191, 245, 220, 79, 189, 93, 101, 69, 139, 76, 115, - 50, 176, 17, 248, 92, 90, 164, 247, 161, 171, 5, 122, 189, 196, 196, 66, 244, 153, 153, 71, - 115, 77, 64, 170, 99, 107, 104, 247, 203, 194, 73, 39, 223, 114, 133, 173, 168, 188, 208, 144, - 230, 249, 24, 120, 52, 18, 144, 188, 164, 84, 194, 241, 223, 113, 165, 231, 181, 152, 254, 41, - 240, 73, 64, 234, 214, 216, 171, 198, 249, 179, 124, 117, 181, 227, 21, 88, 139, 201, 99, 94, - 182, 137, 64, 49, 209, 57, 79, 45, 174, 180, 237, 177, 0, 192, 84, 117, 162, 245, 229, 181, - 108, 139, 243, 210, 255, 152, 33, 0, 94, 234, 148, 90, 146, 42, 221, 95, 80, 55, 238, 93, 29, - 130, 15, 78, 32, 160, 44, 76, 21, 121, 200, 67, 65, 126, 167, 75, 214, 73, 208, 141, 214, 158, - 78, 7, 192, 156, 247, 205, 120, 212, 60, 245, 215, 170, 209, 61, 234, 57, 186, 21, 3, 201, 140, - 27, 79, 94, 235, 24, 172, 136, 92, 51, 137, 84, 9, 162, 91, 13, 118, 116, 9, 129, 94, 37, 189, - 55, 94, 221, 169, 97, 203, 178, 72, 137, 43, 10, 37, 137, 39, 19, 214, 251, 44, 76, 119, 4, 28, - 219, 57, 31, 20, 137, 195, 106, 191, 245, 220, 79, 189, 93, 101, 69, 139, 76, 115, 50, 176, 17, - 248, 92, 90, 164, 247, 161, 171, 5, 122, 189, 196, 196, 66, 244, 153, 153, 71, 115, 77, 64, - 170, 99, 107, 104, 247, 203, 194, 73, 39, 223, 114, 133, 173, 168, 188, 208, 144, 230, 249, 24, - 120, 52, 18, 144, 188, 164, 84, 194, 241, 223, 113, 165, 231, 181, 152, 254, 41, 240, 73, 64, - 234, 214, 216, 171, 198, 249, 179, 124, 117, 181, 227, 21, 88, 139, 201, 99, 94, 182, 137, 64, - 49, 209, 57, 79, 45, 174, 180, 237, 177, 0, 192, 84, 117, 162, 245, 229, 181, 108, 139, 243, - 210, 255, 152, 33, 0, 94, 234, 148, 90, 146, 42, 221, 95, 80, 55, 238, 93, 29, 130, 15, 78, 32, - 160, 44, 76, 21, 121, 200, 67, 65, 126, 167, 75, 214, 73, 208, 141, 214, 158, 78, 2, 32, 7, 73, - 235, 9, 96, 20, 1, 215, 159, 45, 71, 249, 155, 149, 166, 224, 99, 74, 236, 37, 102, 72, 166, - 58, 55, 21, 85, 217, 244, 243, 72, 75, 32, 1, 13, 36, 205, 80, 43, 186, 90, 203, 147, 164, 116, - 81, 229, 76, 201, 109, 212, 114, 48, 146, 182, 200, 118, 87, 75, 161, 243, 178, 37, 82, 101, 2, - 32, 6, 9, 177, 156, 115, 142, 155, 161, 253, 247, 214, 243, 170, 39, 98, 33, 204, 207, 94, 91, - 84, 148, 82, 246, 133, 44, 70, 182, 42, 226, 140, 51, 32, 6, 167, 188, 136, 203, 46, 86, 45, - 139, 104, 250, 207, 142, 220, 121, 120, 13, 77, 141, 173, 142, 98, 192, 211, 104, 115, 136, 43, - 207, 116, 81, 241, 8, 44, 69, 185, 80, 55, 3, 222, 29, 34, 112, 141, 158, 251, 32, 144, 58, - 236, 247, 40, 69, 163, 108, 139, 175, 154, 118, 150, 145, 155, 186, 129, 74, 156, 34, 239, 170, - 195, 232, 217, 4, 82, 144, 237, 128, 36, 75, 172, 149, 49, 83, 164, 176, 123, 255, 208, 155, - 144, 249, 250, 146, 255, 221, 62, 114, 94, 108, 213, 105, 135, 23, 255, 209, 119, 48, 26, 243, - 196, 116, 100, 241, 131, 127, 39, 175, 8, 157, 247, 51, 21, 63, 74, 243, 121, 94, 98, 189, 204, - 198, 43, 185, 179, 198, 237, 189, 24, 32, 140, 222, 145, 236, 159, 0, 98, 215, 209, 124, 33, - 167, 49, 213, 50, 139, 220, 60, 210, 221, 125, 168, 113, 133, 214, 212, 35, 65, 15, 46, 66, - 236, 230, 143, 236, 201, 133, 220, 194, 11, 113, 221, 162, 252, 140, 61, 144, 114, 7, 147, 163, - 59, 168, 74, 91, 20, 121, 18, 62, 47, 39, 126, 212, 24, 254, 178, 85, 161, 200, 242, 152, 12, - 170, 188, 64, 83, 185, 115, 79, 110, 157, 110, 36, 70, 237, 105, 66, 144, 121, 111, 142, 106, - 110, 205, 82, 243, 51, 105, 97, 181, 211, 187, 170, 237, 19, 228, 114, 218, 82, 26, 79, 205, - 42, 79, 159, 194, 210, 203, 252, 89, 141, 6, 13, 139, 105, 158, 82, 26, 166, 148, 184, 91, 40, - 185, 45, 214, 150, 78, 230, 134, 109, 250, 24, 78, 249, 49, 197, 186, 141, 6, 8, 146, 74, 18, - 85, 100, 13, 160, 41, 134, 108, 126, 43, 243, 252, 80, 45, 42, 32, 73, 154, 141, 94, 93, 87, - 230, 56, 40, 29, 54, 181, 100, 203, 156, 34, 239, 170, 195, 232, 217, 4, 82, 144, 237, 128, 36, - 75, 172, 149, 49, 83, 164, 176, 123, 255, 208, 155, 144, 249, 250, 146, 255, 221, 62, 114, 94, - 108, 213, 105, 135, 23, 255, 209, 119, 48, 26, 243, 196, 116, 100, 241, 131, 127, 39, 175, 8, - 157, 247, 51, 21, 63, 74, 243, 121, 94, 98, 189, 204, 198, 43, 185, 179, 198, 237, 189, 24, 32, - 140, 222, 145, 236, 159, 0, 98, 215, 209, 124, 33, 167, 49, 213, 50, 139, 220, 60, 210, 221, - 125, 168, 113, 133, 214, 212, 35, 65, 15, 46, 66, 236, 230, 143, 236, 201, 133, 220, 194, 11, - 113, 221, 162, 252, 140, 61, 144, 114, 7, 147, 163, 59, 168, 74, 91, 20, 121, 18, 62, 47, 39, - 126, 212, 24, 254, 178, 85, 161, 200, 242, 152, 12, 170, 188, 64, 83, 185, 115, 79, 110, 157, - 110, 36, 70, 237, 105, 66, 144, 121, 111, 142, 106, 110, 205, 82, 243, 51, 105, 97, 181, 211, - 187, 170, 237, 19, 228, 114, 218, 82, 26, 79, 205, 42, 79, 159, 194, 210, 203, 252, 89, 141, 6, - 13, 139, 105, 158, 82, 26, 166, 148, 184, 91, 40, 185, 45, 214, 150, 78, 230, 134, 109, 250, - 24, 78, 249, 49, 197, 186, 141, 6, 36, 32, 5, 67, 65, 187, 226, 147, 101, 55, 58, 16, 241, 10, - 222, 30, 122, 37, 116, 98, 22, 42, 33, 141, 241, 197, 84, 85, 235, 89, 96, 51, 5, 148, 32, 7, - 57, 166, 250, 191, 201, 145, 30, 36, 33, 78, 36, 110, 97, 41, 23, 14, 208, 158, 12, 171, 238, - 42, 24, 91, 244, 153, 174, 242, 29, 141, 238, 32, 3, 16, 204, 119, 247, 145, 22, 195, 161, 228, - 105, 160, 17, 110, 233, 99, 231, 165, 51, 57, 130, 189, 131, 150, 20, 207, 140, 114, 217, 190, - 119, 155, 32, 1, 84, 54, 105, 1, 55, 44, 91, 134, 14, 245, 124, 185, 191, 101, 16, 224, 223, - 52, 105, 164, 87, 116, 234, 252, 114, 221, 170, 210, 119, 197, 160, 32, 2, 121, 230, 186, 66, - 142, 126, 114, 149, 48, 233, 26, 133, 252, 126, 117, 215, 180, 161, 174, 109, 20, 244, 214, - 208, 85, 76, 221, 212, 76, 95, 87, 32, 7, 161, 87, 170, 89, 229, 183, 27, 195, 82, 69, 132, - 104, 217, 130, 238, 151, 136, 174, 144, 184, 168, 140, 234, 36, 3, 176, 245, 25, 125, 41, 99, - 32, 0, 88, 67, 92, 71, 241, 32, 23, 38, 147, 66, 114, 209, 11, 251, 35, 112, 6, 86, 246, 23, - 45, 18, 208, 40, 24, 7, 103, 142, 243, 208, 70, 32, 0, 44, 33, 174, 35, 248, 144, 11, 147, 73, - 161, 57, 104, 133, 253, 145, 184, 3, 43, 123, 11, 150, 137, 104, 20, 12, 3, 179, 199, 121, 232, - 35, 32, 0, 190, 153, 0, 87, 9, 24, 136, 55, 141, 84, 141, 190, 137, 98, 86, 14, 167, 124, 221, - 20, 103, 195, 105, 147, 214, 11, 57, 232, 95, 60, 79, 32, 7, 2, 75, 27, 144, 45, 141, 18, 17, - 197, 29, 209, 193, 41, 103, 212, 203, 69, 251, 58, 229, 64, 68, 251, 196, 233, 158, 44, 7, 57, - 77, 100, 32, 3, 206, 150, 159, 110, 197, 166, 239, 109, 88, 196, 252, 96, 243, 114, 21, 183, - 251, 127, 145, 101, 84, 97, 22, 11, 151, 10, 216, 49, 162, 201, 213, 32, 3, 114, 96, 155, 157, - 209, 179, 39, 101, 148, 71, 255, 233, 3, 119, 212, 135, 111, 200, 173, 68, 173, 210, 162, 34, - 207, 12, 33, 180, 115, 164, 222, 32, 5, 102, 58, 97, 209, 193, 218, 107, 34, 46, 13, 224, 179, - 255, 212, 219, 152, 247, 162, 11, 146, 32, 247, 155, 254, 13, 124, 237, 185, 121, 20, 46, 32, - 3, 63, 36, 54, 81, 52, 160, 17, 1, 67, 68, 98, 127, 193, 149, 149, 108, 62, 236, 210, 156, 74, - 13, 68, 24, 49, 126, 219, 124, 12, 217, 131, 32, 2, 72, 26, 68, 109, 167, 32, 138, 238, 138, - 38, 34, 74, 39, 46, 87, 232, 197, 93, 136, 220, 193, 133, 87, 149, 232, 200, 205, 194, 168, - 180, 255, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 32, 6, 157, 51, 20, 126, 24, 171, 219, 83, 113, 176, 134, 159, 213, 92, 150, - 133, 67, 235, 2, 44, 141, 134, 94, 252, 183, 45, 81, 178, 193, 187, 88, 32, 7, 39, 244, 27, - 175, 73, 179, 134, 107, 184, 136, 76, 211, 49, 69, 110, 221, 22, 113, 80, 88, 44, 157, 146, - 196, 227, 83, 126, 41, 3, 139, 54, 32, 1, 49, 232, 14, 7, 76, 32, 178, 247, 39, 65, 91, 29, - 231, 93, 9, 136, 36, 176, 72, 92, 63, 78, 121, 43, 48, 56, 66, 70, 133, 99, 48, 32, 0, 145, - 154, 219, 32, 156, 27, 197, 255, 214, 192, 230, 207, 33, 197, 55, 174, 39, 213, 138, 192, 238, - 173, 22, 247, 249, 93, 8, 176, 31, 109, 71, 32, 2, 243, 229, 117, 197, 255, 122, 250, 110, 201, - 31, 116, 254, 193, 241, 228, 98, 239, 97, 168, 95, 254, 50, 197, 37, 219, 228, 30, 1, 75, 37, - 146, 32, 2, 251, 95, 40, 126, 75, 198, 15, 89, 219, 83, 79, 188, 119, 46, 143, 32, 239, 124, - 60, 150, 0, 99, 126, 170, 74, 181, 237, 134, 110, 55, 6, 32, 6, 149, 5, 76, 142, 231, 0, 142, - 241, 181, 85, 73, 250, 247, 101, 96, 235, 88, 30, 55, 194, 36, 239, 22, 72, 194, 253, 245, 170, - 77, 86, 138, 32, 1, 130, 28, 118, 182, 141, 212, 15, 115, 26, 105, 190, 143, 91, 142, 125, 93, - 179, 212, 15, 84, 203, 43, 152, 249, 215, 69, 53, 127, 186, 4, 123, 32, 7, 188, 212, 79, 117, - 224, 48, 21, 132, 24, 203, 184, 43, 159, 57, 44, 102, 65, 62, 39, 35, 169, 155, 34, 206, 199, - 163, 103, 4, 20, 100, 230, 32, 7, 177, 217, 196, 41, 199, 253, 106, 197, 179, 235, 189, 122, - 190, 152, 124, 130, 168, 39, 48, 150, 172, 176, 249, 186, 184, 183, 153, 193, 183, 190, 48, 32, - 6, 90, 178, 87, 183, 16, 44, 145, 121, 253, 254, 45, 149, 160, 193, 42, 145, 252, 195, 180, - 150, 92, 184, 72, 197, 24, 248, 54, 251, 236, 40, 157, 32, 2, 20, 178, 102, 77, 107, 189, 105, - 174, 137, 145, 138, 75, 136, 55, 149, 196, 168, 35, 11, 98, 2, 184, 73, 172, 135, 147, 69, 196, - 45, 250, 210, 32, 1, 14, 10, 106, 98, 138, 75, 176, 118, 144, 9, 206, 43, 165, 78, 196, 34, - 253, 229, 32, 158, 41, 166, 34, 95, 227, 24, 235, 84, 92, 131, 172, 32, 4, 133, 28, 17, 71, - 214, 252, 106, 118, 134, 29, 190, 64, 157, 56, 44, 222, 229, 18, 91, 194, 37, 190, 132, 97, 76, - 179, 57, 46, 209, 5, 252, 32, 6, 99, 7, 73, 218, 173, 225, 144, 13, 237, 152, 82, 222, 52, 173, - 137, 235, 94, 44, 138, 79, 181, 153, 108, 186, 165, 54, 135, 8, 9, 242, 235, 32, 5, 48, 127, - 150, 223, 172, 207, 58, 53, 228, 107, 136, 242, 14, 98, 85, 248, 152, 107, 106, 155, 84, 180, - 62, 11, 170, 99, 26, 119, 0, 26, 152, 32, 5, 150, 111, 125, 40, 103, 113, 4, 198, 91, 120, 42, - 55, 194, 34, 156, 213, 118, 98, 226, 116, 37, 35, 58, 203, 240, 123, 124, 167, 27, 86, 117, 32, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 32, 7, 255, 255, 255, 254, 239, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 225, 36, 32, 5, 113, 4, - 132, 41, 62, 211, 190, 57, 115, 226, 29, 236, 84, 66, 103, 143, 107, 143, 132, 0, 189, 123, 89, - 115, 151, 114, 173, 78, 206, 16, 27, 32, 5, 178, 169, 38, 158, 45, 64, 176, 152, 162, 46, 4, - 130, 160, 119, 48, 93, 180, 26, 159, 93, 16, 75, 9, 55, 73, 82, 63, 231, 143, 90, 240, 32, 5, - 129, 28, 11, 54, 157, 116, 223, 41, 180, 53, 230, 180, 162, 192, 75, 115, 52, 231, 160, 198, - 165, 202, 235, 171, 121, 171, 248, 69, 239, 171, 165, 32, 4, 148, 123, 66, 220, 147, 249, 219, - 22, 50, 133, 191, 3, 46, 204, 32, 255, 78, 7, 216, 144, 240, 197, 105, 37, 253, 144, 63, 219, - 5, 224, 19, 32, 3, 60, 206, 209, 73, 124, 219, 99, 213, 107, 200, 77, 39, 69, 30, 196, 245, 99, - 97, 155, 149, 23, 235, 133, 94, 106, 143, 237, 20, 113, 57, 16, 32, 6, 215, 232, 251, 136, 70, - 80, 241, 31, 10, 243, 237, 69, 23, 106, 178, 191, 65, 191, 22, 80, 78, 140, 254, 147, 136, 197, - 229, 171, 60, 73, 82, 32, 2, 73, 154, 109, 136, 227, 115, 86, 25, 32, 98, 40, 10, 104, 153, - 159, 21, 207, 107, 83, 67, 122, 144, 110, 234, 176, 129, 215, 92, 124, 242, 167, 32, 5, 36, - 205, 54, 196, 113, 185, 179, 140, 144, 49, 20, 5, 52, 76, 207, 138, 231, 181, 169, 161, 189, - 72, 55, 117, 88, 64, 235, 174, 62, 121, 84, 32, 5, 68, 225, 208, 192, 61, 230, 9, 15, 223, 141, - 211, 67, 156, 13, 203, 95, 95, 222, 131, 139, 121, 135, 42, 245, 42, 225, 196, 87, 150, 110, - 215, 32, 0, 48, 249, 21, 152, 12, 29, 189, 81, 197, 24, 228, 71, 100, 241, 213, 176, 240, 172, - 174, 58, 244, 166, 105, 180, 141, 41, 211, 204, 144, 52, 119, 32, 4, 158, 53, 245, 127, 169, - 138, 163, 190, 77, 178, 159, 168, 221, 104, 97, 40, 84, 47, 51, 32, 182, 223, 132, 101, 228, - 253, 118, 155, 61, 39, 204, 32, 1, 218, 189, 154, 24, 70, 25, 7, 212, 212, 9, 239, 129, 206, - 195, 175, 250, 196, 246, 46, 161, 224, 5, 132, 160, 134, 49, 255, 101, 109, 171, 227, 32, 5, - 24, 157, 127, 103, 49, 148, 150, 136, 145, 89, 44, 171, 187, 246, 34, 174, 33, 106, 73, 106, - 110, 254, 60, 162, 243, 176, 254, 18, 117, 217, 51, 32, 3, 228, 135, 71, 204, 17, 246, 220, - 230, 229, 141, 177, 226, 139, 118, 94, 18, 181, 218, 211, 157, 25, 217, 183, 65, 164, 213, 166, - 183, 18, 238, 125, 32, 0, 164, 190, 217, 68, 14, 4, 149, 61, 10, 60, 34, 50, 71, 162, 146, 163, - 70, 241, 24, 137, 39, 207, 234, 219, 81, 44, 33, 220, 0, 169, 107, 32, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 6, 149, 17, 221, - 202, 105, 0, 31, 33, 26, 217, 147, 78, 247, 103, 12, 128, 28, 193, 247, 88, 242, 51, 131, 79, - 111, 43, 121, 15, 105, 25, 22, 32, 7, 254, 27, 57, 67, 21, 121, 98, 12, 174, 115, 93, 211, 254, - 204, 55, 232, 22, 4, 49, 56, 27, 28, 183, 62, 74, 166, 103, 103, 84, 58, 71, 32, 3, 116, 89, - 217, 70, 248, 192, 197, 108, 66, 140, 160, 141, 248, 42, 92, 236, 59, 59, 118, 143, 222, 223, - 51, 13, 91, 20, 29, 2, 235, 222, 151, 32, 3, 233, 228, 245, 165, 212, 209, 212, 118, 120, 80, - 237, 22, 221, 66, 138, 123, 227, 47, 177, 61, 67, 228, 207, 198, 235, 236, 24, 167, 22, 69, 57, - 32, 0, 167, 220, 91, 5, 166, 130, 243, 38, 200, 208, 20, 171, 72, 125, 142, 242, 87, 141, 131, - 207, 224, 63, 172, 154, 165, 16, 140, 211, 85, 229, 155, 32, 1, 187, 10, 218, 105, 114, 29, 65, - 28, 236, 65, 201, 231, 214, 125, 89, 45, 16, 18, 67, 29, 220, 10, 134, 50, 174, 92, 75, 157, - 210, 25, 226, 32, 1, 162, 222, 29, 125, 140, 22, 50, 197, 50, 193, 120, 51, 189, 79, 43, 130, - 243, 16, 145, 195, 16, 89, 144, 212, 141, 96, 70, 233, 137, 71, 86, 32, 1, 53, 111, 177, 148, - 38, 252, 138, 106, 253, 254, 51, 189, 137, 67, 217, 198, 10, 50, 215, 34, 236, 120, 116, 86, - 141, 179, 242, 113, 190, 94, 149, 32, 7, 85, 179, 63, 144, 238, 1, 2, 243, 105, 223, 39, 168, - 36, 16, 104, 16, 101, 213, 7, 195, 16, 225, 251, 50, 116, 6, 54, 222, 193, 249, 106, 32, 1, - 243, 144, 133, 144, 53, 44, 106, 28, 171, 117, 167, 125, 229, 3, 94, 231, 111, 69, 162, 147, - 117, 120, 177, 130, 168, 13, 102, 120, 1, 68, 100, 32, 2, 115, 110, 122, 204, 241, 7, 97, 255, - 207, 137, 222, 176, 43, 103, 188, 223, 109, 97, 219, 46, 175, 66, 88, 158, 213, 204, 249, 182, - 122, 60, 32, 32, 4, 116, 237, 160, 162, 120, 154, 57, 103, 83, 24, 167, 167, 171, 109, 113, - 154, 127, 65, 11, 127, 101, 75, 54, 29, 191, 250, 131, 185, 132, 144, 113, 32, 6, 64, 89, 16, - 14, 28, 156, 232, 240, 95, 165, 200, 103, 135, 237, 37, 237, 54, 239, 7, 237, 0, 67, 167, 164, - 168, 224, 41, 173, 195, 93, 58, 32, 0, 163, 210, 15, 175, 253, 202, 171, 103, 170, 213, 57, 27, - 122, 238, 152, 153, 51, 232, 115, 193, 41, 145, 51, 237, 50, 57, 199, 72, 137, 185, 204, 32, 3, - 234, 223, 251, 69, 119, 7, 60, 185, 191, 161, 181, 126, 115, 59, 120, 53, 102, 193, 71, 170, - 44, 109, 9, 178, 70, 59, 85, 0, 43, 122, 23, 32, 1, 23, 143, 177, 10, 146, 76, 7, 182, 122, 8, - 57, 75, 111, 126, 122, 130, 218, 140, 246, 169, 115, 201, 66, 131, 194, 50, 179, 128, 32, 14, - 38, 32, 1, 17, 140, 170, 61, 218, 5, 177, 217, 117, 34, 160, 216, 36, 165, 117, 187, 250, 50, - 7, 187, 193, 228, 26, 4, 16, 182, 169, 164, 182, 255, 71, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 254, - 239, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 239, 255, 225, 1, 8, 53, 76, 190, 184, 244, 36, 126, 255, 134, 180, - 213, 61, 112, 41, 244, 182, 188, 22, 10, 147, 91, 158, 90, 131, 148, 157, 56, 245, 63, 60, 132, - 97, 179, 21, 130, 172, 74, 138, 253, 38, 56, 180, 102, 39, 111, 136, 166, 55, 53, 85, 254, 63, - 223, 5, 225, 253, 154, 57, 29, 217, 247, 8, 124, 152, 135, 34, 188, 151, 17, 187, 220, 0, 165, - 108, 251, 46, 107, 166, 181, 205, 71, 218, 163, 122, 119, 132, 70, 149, 13, 167, 45, 27, 16, - 248, 130, 246, 62, 140, 105, 159, 88, 38, 247, 37, 228, 16, 114, 143, 17, 195, 241, 138, 53, - 178, 151, 238, 26, 248, 33, 227, 5, 41, 194, 29, 250, 21, 194, 122, 94, 135, 249, 215, 243, 35, - 175, 188, 241, 148, 240, 29, 134, 150, 249, 169, 156, 239, 74, 76, 156, 247, 185, 194, 128, 66, - 214, 36, 211, 116, 90, 38, 107, 227, 92, 168, 83, 134, 109, 180, 211, 28, 204, 33, 14, 245, 72, - 86, 236, 114, 107, 238, 242, 209, 141, 32, 188, 207, 90, 66, 55, 99, 210, 105, 248, 192, 4, 62, - 145, 208, 140, 147, 51, 213, 13, 119, 168, 48, 157, 15, 196, 33, 110, 183, 87, 150, 74, 188, - 70, 155, 201, 215, 23, 246, 142, 253, 16, 200, 158, 124, 254, 165, 5, 73, 12, 53, 221, 137, - 122, 171, 78, 203, 75, 123, 4, 181, 50, 42, 37, 32, 13, 234, 176, 114, 190, 190, 94, 157, 8, - 34, 114, 134, 201, 115, 56, 140, 49, 142, 12, 86, 177, 21, 174, 54, 113, 237, 107, 139, 115, - 165, 7, 246, 48, 26, 84, 165, 99, 169, 89, 113, 30, 179, 21, 130, 172, 74, 138, 253, 38, 56, - 180, 102, 39, 111, 136, 166, 55, 53, 85, 254, 63, 223, 5, 225, 253, 154, 57, 29, 217, 247, 8, - 124, 152, 135, 34, 188, 151, 17, 187, 220, 0, 165, 108, 251, 46, 107, 166, 181, 205, 71, 218, - 163, 122, 119, 132, 70, 149, 13, 167, 45, 27, 16, 248, 130, 246, 62, 140, 105, 159, 88, 38, - 247, 37, 228, 16, 114, 143, 17, 195, 241, 138, 53, 178, 151, 238, 26, 248, 33, 227, 5, 41, 194, - 29, 250, 21, 194, 122, 94, 135, 249, 215, 243, 35, 175, 188, 241, 148, 240, 29, 134, 150, 249, - 169, 156, 239, 74, 76, 156, 247, 185, 194, 128, 66, 214, 36, 211, 116, 90, 38, 107, 227, 92, - 168, 83, 134, 109, 180, 211, 28, 204, 33, 14, 245, 72, 86, 236, 114, 107, 238, 242, 209, 141, - 32, 188, 207, 90, 66, 55, 99, 210, 105, 248, 192, 4, 62, 145, 208, 140, 147, 51, 213, 13, 119, - 168, 48, 157, 15, 196, 33, 110, 183, 87, 150, 74, 188, 70, 155, 201, 215, 23, 246, 142, 253, - 16, 200, 158, 124, 254, 165, 5, 73, 12, 53, 221, 137, 122, 171, 78, 203, 75, 123, 4, 181, 50, - 42, 37, 32, 13, 234, 176, 114, 190, 190, 94, 157, 23, 32, 5, 186, 158, 17, 4, 199, 30, 144, - 201, 38, 11, 250, 108, 122, 224, 128, 16, 54, 3, 22, 121, 52, 205, 27, 220, 62, 254, 5, 5, 96, - 103, 139, 32, 7, 59, 132, 58, 0, 159, 27, 9, 41, 149, 70, 135, 241, 46, 173, 1, 149, 22, 148, - 213, 68, 148, 155, 241, 153, 175, 198, 3, 251, 1, 177, 222, 32, 7, 59, 132, 58, 0, 159, 27, 9, - 41, 149, 70, 135, 241, 46, 173, 1, 149, 22, 148, 213, 68, 148, 155, 241, 153, 175, 198, 3, 251, - 1, 177, 222, 32, 7, 59, 132, 58, 0, 159, 27, 9, 41, 149, 70, 135, 241, 46, 173, 1, 149, 22, - 148, 213, 68, 148, 155, 241, 153, 175, 198, 3, 251, 1, 177, 222, 32, 0, 105, 212, 236, 199, - 239, 28, 54, 213, 225, 236, 74, 163, 155, 99, 70, 108, 178, 43, 245, 88, 11, 111, 170, 159, - 159, 33, 58, 96, 204, 29, 11, 32, 3, 206, 0, 174, 2, 104, 127, 150, 87, 237, 207, 22, 241, 3, - 9, 155, 152, 245, 234, 183, 232, 240, 217, 138, 46, 74, 161, 162, 39, 132, 23, 77, 32, 5, 208, - 70, 213, 49, 253, 16, 182, 213, 162, 3, 62, 154, 172, 201, 108, 198, 33, 9, 163, 29, 246, 138, - 142, 204, 208, 212, 219, 227, 218, 38, 125, 32, 5, 137, 156, 64, 105, 64, 51, 90, 199, 221, 86, - 116, 210, 235, 217, 67, 53, 99, 154, 234, 105, 110, 151, 32, 128, 61, 53, 240, 217, 19, 140, - 135, 32, 1, 32, 30, 162, 132, 42, 50, 45, 45, 82, 75, 169, 1, 127, 111, 8, 159, 37, 72, 164, - 217, 124, 74, 113, 81, 8, 196, 143, 85, 201, 211, 146, 32, 7, 192, 192, 46, 130, 184, 228, 219, - 107, 64, 19, 135, 51, 19, 38, 223, 184, 90, 194, 80, 30, 108, 99, 89, 69, 28, 35, 126, 196, 2, - 204, 98, 32, 1, 45, 221, 64, 177, 51, 59, 84, 97, 184, 119, 103, 199, 85, 35, 64, 59, 125, 12, - 239, 233, 77, 17, 59, 132, 59, 163, 179, 135, 199, 20, 223, 32, 1, 2, 251, 108, 216, 187, 36, - 189, 54, 162, 37, 18, 116, 131, 155, 30, 145, 213, 19, 36, 123, 201, 153, 119, 20, 216, 85, - 135, 36, 110, 185, 46, 32, 6, 123, 154, 60, 47, 212, 237, 207, 194, 253, 45, 101, 86, 179, 69, - 3, 34, 103, 64, 50, 131, 172, 22, 51, 87, 73, 218, 82, 220, 93, 150, 119, 32, 5, 120, 233, 13, - 54, 248, 167, 31, 72, 6, 136, 240, 245, 243, 230, 176, 66, 93, 46, 150, 109, 126, 60, 152, 221, - 91, 157, 136, 87, 139, 136, 234, 32, 4, 143, 65, 110, 148, 247, 167, 104, 3, 87, 209, 157, 58, - 96, 39, 81, 37, 2, 216, 55, 134, 215, 85, 47, 154, 183, 17, 242, 100, 50, 158, 95, 32, 0, 64, - 107, 195, 205, 225, 33, 232, 80, 95, 118, 77, 242, 68, 226, 166, 76, 13, 158, 58, 156, 126, 1, - 39, 113, 228, 237, 125, 194, 71, 219, 243, 32, 3, 203, 42, 99, 32, 148, 99, 137, 238, 191, 1, - 36, 39, 248, 146, 42, 50, 42, 150, 226, 174, 228, 246, 140, 163, 221, 70, 172, 9, 224, 161, - 141, 32, 1, 164, 166, 114, 98, 225, 94, 86, 220, 67, 159, 142, 200, 239, 158, 128, 59, 63, 244, - 200, 149, 178, 88, 122, 153, 159, 43, 229, 99, 130, 176, 213, 32, 6, 169, 97, 59, 109, 42, 177, - 241, 154, 69, 148, 121, 125, 6, 94, 174, 66, 175, 11, 229, 220, 249, 18, 34, 2, 160, 9, 239, - 122, 119, 121, 83, 32, 0, 113, 217, 179, 47, 12, 210, 21, 180, 101, 98, 32, 129, 125, 69, 23, - 156, 167, 69, 139, 17, 110, 127, 16, 32, 226, 158, 43, 211, 208, 95, 106, 32, 6, 66, 54, 132, - 34, 88, 227, 47, 71, 74, 74, 117, 11, 188, 95, 242, 236, 119, 26, 90, 56, 194, 126, 180, 87, - 48, 21, 155, 142, 228, 230, 211, 32, 1, 8, 232, 148, 173, 220, 235, 206, 152, 38, 185, 100, - 198, 14, 72, 189, 13, 12, 212, 47, 115, 244, 123, 221, 143, 219, 156, 97, 194, 199, 30, 182, - 32, 7, 142, 85, 159, 235, 76, 225, 193, 220, 214, 98, 183, 199, 106, 5, 128, 73, 21, 138, 21, - 133, 93, 23, 96, 224, 25, 220, 170, 83, 210, 66, 181, 23, 32, 2, 163, 37, 122, 174, 56, 142, - 216, 245, 244, 184, 125, 39, 223, 238, 134, 178, 190, 78, 68, 69, 240, 60, 60, 85, 185, 29, - 136, 8, 47, 77, 48, 32, 5, 134, 123, 84, 149, 88, 171, 143, 12, 2, 179, 5, 248, 244, 63, 61, - 250, 98, 223, 173, 74, 59, 42, 3, 141, 127, 106, 217, 226, 16, 176, 72, 32, 5, 134, 123, 84, - 149, 88, 171, 143, 12, 2, 179, 5, 248, 244, 63, 61, 250, 98, 223, 173, 74, 59, 42, 3, 141, 127, - 106, 217, 226, 16, 176, 72, 32, 5, 134, 123, 84, 149, 88, 171, 143, 12, 2, 179, 5, 248, 244, - 63, 61, 250, 98, 223, 173, 74, 59, 42, 3, 141, 127, 106, 217, 226, 16, 176, 72, 32, 4, 92, 215, - 77, 64, 206, 190, 217, 231, 204, 138, 52, 187, 225, 6, 195, 184, 148, 146, 98, 142, 10, 237, - 132, 238, 196, 103, 185, 79, 194, 106, 136, 32, 3, 46, 151, 117, 185, 146, 93, 232, 151, 44, - 106, 244, 141, 173, 239, 52, 56, 135, 91, 188, 25, 179, 249, 178, 233, 219, 75, 220, 85, 224, - 185, 209, 32, 2, 56, 187, 99, 96, 73, 48, 196, 162, 85, 121, 87, 137, 132, 0, 59, 48, 163, 133, - 42, 64, 251, 175, 198, 248, 130, 201, 199, 19, 56, 163, 114, 32, 2, 172, 72, 17, 36, 178, 144, - 116, 175, 221, 11, 124, 163, 187, 41, 241, 245, 235, 100, 187, 15, 172, 6, 189, 60, 251, 173, - 63, 2, 144, 176, 203, 32, 7, 194, 200, 168, 120, 214, 176, 202, 129, 184, 40, 234, 93, 192, 96, - 149, 93, 27, 207, 30, 82, 103, 197, 14, 57, 60, 237, 110, 40, 137, 127, 178, 32, 0, 146, 147, - 27, 150, 232, 183, 159, 61, 81, 156, 49, 23, 171, 214, 123, 84, 145, 61, 177, 155, 161, 247, - 107, 159, 235, 213, 8, 223, 170, 234, 88, 32, 3, 48, 147, 58, 168, 56, 95, 160, 86, 124, 159, - 140, 248, 6, 18, 224, 187, 96, 136, 232, 45, 215, 140, 153, 173, 36, 239, 28, 65, 147, 132, - 227, 32, 1, 39, 121, 52, 204, 102, 136, 60, 217, 100, 93, 56, 68, 161, 91, 53, 36, 118, 239, - 179, 199, 132, 39, 21, 134, 8, 127, 77, 214, 86, 1, 151, 32, 7, 15, 168, 86, 36, 5, 223, 136, - 141, 130, 114, 241, 60, 171, 135, 22, 64, 144, 76, 189, 171, 105, 238, 199, 215, 248, 15, 43, - 124, 82, 216, 100, 32, 6, 63, 121, 168, 212, 175, 97, 183, 41, 55, 6, 157, 118, 25, 237, 140, - 10, 226, 38, 108, 72, 133, 2, 20, 194, 105, 90, 234, 237, 127, 31, 135, 32, 3, 95, 90, 246, - 146, 220, 220, 126, 124, 221, 229, 120, 229, 121, 95, 66, 18, 111, 5, 39, 64, 234, 189, 232, - 60, 159, 0, 147, 67, 124, 160, 81, 32, 0, 128, 196, 177, 18, 102, 194, 247, 111, 5, 184, 24, - 121, 42, 79, 59, 157, 32, 59, 47, 201, 87, 49, 140, 36, 207, 154, 233, 55, 156, 85, 20, 32, 6, - 62, 129, 192, 53, 29, 18, 19, 220, 210, 210, 124, 2, 184, 146, 46, 63, 85, 62, 153, 96, 202, - 189, 179, 217, 249, 228, 208, 168, 157, 171, 85, 32, 4, 252, 20, 112, 128, 70, 142, 15, 151, - 58, 44, 107, 29, 87, 123, 89, 197, 199, 250, 144, 132, 224, 120, 23, 72, 171, 230, 249, 115, - 103, 168, 121, 32, 4, 60, 231, 255, 193, 168, 52, 217, 217, 202, 195, 20, 89, 217, 87, 29, 192, - 63, 88, 181, 124, 111, 98, 76, 244, 242, 19, 120, 128, 217, 152, 2, 32, 0, 191, 48, 142, 1, - 122, 139, 54, 112, 203, 106, 113, 208, 27, 51, 82, 50, 5, 74, 173, 182, 74, 138, 26, 102, 72, - 156, 187, 195, 46, 2, 64, 32, 6, 255, 188, 219, 98, 117, 141, 235, 142, 127, 232, 100, 141, - 181, 71, 41, 93, 30, 54, 159, 61, 216, 140, 181, 69, 141, 233, 175, 62, 217, 202, 156, 32, 4, - 99, 247, 11, 27, 207, 183, 69, 247, 182, 4, 61, 13, 223, 66, 13, 24, 87, 237, 199, 6, 87, 70, - 190, 204, 21, 255, 59, 202, 68, 204, 246, 32, 5, 225, 146, 39, 232, 171, 250, 119, 5, 75, 119, - 156, 34, 22, 69, 148, 221, 12, 244, 207, 17, 223, 208, 148, 99, 157, 19, 211, 91, 251, 107, - 184, 7, 252, 11, 21, 38, 31, 183, 75, 252, 11, 109, 101, 0, 223, 66, 171, 63, 19, 183, 139, - 142, 40, 174, 191, 87, 11, 222, 129, 124, 101, 75, 123, 70, 199, 158, 120, 185, 8, 172, 104, - 202, 129, 51, 166, 239, 100, 28, 87, 199, 146, 146, 226, 245, 22, 221, 52, 20, 178, 168, 107, - 218, 157, 192, 83, 17, 243, 148, 90, 0, 157, 43, 19, 77, 53, 64, 134, 77, 63, 197, 63, 243, 41, - 44, 218, 23, 127, 103, 9, 194, 201, 58, 143, 151, 62, 85, 75, 217, 143, 98, 74, 76, 140, 137, - 217, 143, 157, 127, 73, 13, 30, 154, 115, 104, 31, 52, 74, 172, 134, 205, 100, 44, 195, 181, - 60, 156, 125, 108, 163, 218, 226, 24, 112, 45, 211, 8, 154, 246, 16, 159, 237, 206, 177, 157, - 162, 154, 64, 186, 79, 84, 23, 81, 132, 104, 72, 66, 186, 25, 81, 168, 118, 233, 92, 41, 171, - 144, 132, 246, 76, 246, 142, 86, 209, 111, 24, 65, 183, 87, 141, 130, 215, 53, 217, 166, 72, - 61, 175, 41, 33, 248, 102, 55, 7, 57, 90, 146, 42, 221, 95, 80, 55, 238, 93, 29, 130, 15, 78, - 32, 160, 44, 76, 21, 121, 200, 67, 65, 126, 167, 75, 214, 73, 208, 141, 214, 158, 78, 7, 252, - 11, 21, 38, 31, 183, 75, 252, 11, 109, 101, 0, 223, 66, 171, 63, 19, 183, 139, 142, 40, 174, - 191, 87, 11, 222, 129, 124, 101, 75, 123, 70, 199, 158, 120, 185, 8, 172, 104, 202, 129, 51, - 166, 239, 100, 28, 87, 199, 146, 146, 226, 245, 22, 221, 52, 20, 178, 168, 107, 218, 157, 192, - 83, 17, 243, 148, 90, 0, 157, 43, 19, 77, 53, 64, 134, 77, 63, 197, 63, 243, 41, 44, 218, 23, - 127, 103, 9, 194, 201, 58, 143, 151, 62, 85, 75, 217, 143, 98, 74, 76, 140, 137, 217, 143, 157, - 127, 73, 13, 30, 154, 115, 104, 31, 52, 74, 172, 134, 205, 100, 44, 195, 181, 60, 156, 125, - 108, 163, 218, 226, 24, 112, 45, 211, 8, 154, 246, 16, 159, 237, 206, 177, 157, 162, 154, 64, - 186, 79, 84, 23, 81, 132, 104, 72, 66, 186, 25, 81, 168, 118, 233, 92, 41, 171, 144, 132, 246, - 76, 246, 142, 86, 209, 111, 24, 65, 183, 87, 141, 130, 215, 53, 217, 166, 72, 61, 175, 41, 33, - 248, 102, 55, 7, 57, 90, 146, 42, 221, 95, 80, 55, 238, 93, 29, 130, 15, 78, 32, 160, 44, 76, - 21, 121, 200, 67, 65, 126, 167, 75, 214, 73, 208, 141, 214, 158, 78, 2, 32, 0, 179, 251, 140, - 44, 139, 6, 94, 64, 141, 189, 35, 254, 12, 27, 211, 162, 142, 138, 211, 124, 152, 90, 62, 191, - 1, 150, 162, 11, 201, 237, 84, 32, 0, 5, 52, 81, 173, 157, 123, 17, 228, 220, 86, 223, 6, 220, - 169, 67, 186, 126, 121, 118, 203, 118, 138, 201, 72, 162, 221, 245, 67, 29, 54, 105, 2, 32, 4, - 59, 167, 10, 174, 78, 27, 164, 37, 184, 185, 58, 172, 94, 255, 217, 40, 43, 224, 65, 187, 205, - 196, 83, 218, 117, 172, 94, 162, 228, 116, 187, 32, 0, 59, 195, 41, 28, 105, 216, 158, 77, 47, - 61, 181, 95, 59, 232, 102, 220, 180, 100, 248, 53, 31, 84, 26, 212, 152, 188, 91, 145, 245, - 173, 130, 8, 72, 157, 52, 65, 131, 107, 51, 203, 161, 9, 236, 138, 220, 146, 47, 117, 159, 8, - 235, 198, 120, 15, 215, 252, 32, 210, 210, 40, 184, 17, 38, 68, 138, 172, 80, 210, 73, 228, - 117, 59, 0, 40, 28, 69, 91, 166, 191, 11, 97, 172, 37, 28, 174, 5, 94, 106, 50, 248, 229, 59, - 162, 89, 94, 231, 74, 147, 252, 163, 246, 133, 208, 151, 87, 189, 40, 208, 243, 159, 219, 5, - 173, 34, 96, 18, 158, 19, 99, 83, 193, 175, 94, 97, 238, 97, 169, 236, 150, 245, 207, 203, 230, - 180, 210, 239, 201, 38, 87, 47, 79, 103, 91, 115, 144, 169, 207, 195, 17, 196, 182, 226, 74, - 106, 171, 149, 236, 195, 101, 146, 225, 111, 62, 174, 168, 68, 214, 215, 129, 69, 23, 126, 173, - 62, 129, 192, 223, 180, 220, 93, 110, 122, 57, 46, 181, 95, 198, 39, 137, 90, 39, 24, 90, 125, - 16, 25, 41, 188, 114, 58, 89, 239, 63, 64, 105, 4, 102, 211, 3, 43, 180, 109, 69, 210, 168, 47, - 199, 3, 231, 17, 41, 201, 253, 197, 66, 155, 36, 12, 34, 61, 169, 95, 84, 39, 35, 149, 250, - 234, 76, 165, 17, 124, 40, 205, 185, 201, 27, 71, 191, 77, 148, 228, 244, 148, 31, 91, 252, 89, - 141, 6, 13, 139, 105, 158, 82, 26, 166, 148, 184, 91, 40, 185, 45, 214, 150, 78, 230, 134, 109, - 250, 24, 78, 249, 49, 197, 186, 141, 6, 8, 80, 32, 245, 250, 73, 182, 254, 224, 221, 201, 126, - 136, 9, 100, 226, 76, 104, 161, 124, 29, 227, 115, 194, 205, 218, 183, 229, 180, 154, 171, 16, - 114, 138, 172, 80, 210, 73, 228, 117, 59, 0, 40, 28, 69, 91, 166, 191, 11, 97, 172, 37, 28, - 174, 5, 94, 106, 50, 248, 229, 59, 162, 89, 94, 231, 74, 147, 252, 163, 246, 133, 208, 151, 87, - 189, 40, 208, 243, 159, 219, 5, 173, 34, 96, 18, 158, 19, 99, 83, 193, 175, 94, 97, 238, 97, - 169, 236, 150, 245, 207, 203, 230, 180, 210, 239, 201, 38, 87, 47, 79, 103, 91, 115, 144, 169, - 207, 195, 17, 196, 182, 226, 74, 106, 171, 149, 236, 195, 101, 146, 225, 111, 62, 174, 168, 68, - 214, 215, 129, 69, 23, 126, 173, 62, 129, 192, 223, 180, 220, 93, 110, 122, 57, 46, 181, 95, - 198, 39, 137, 90, 39, 24, 90, 125, 16, 25, 41, 188, 114, 58, 89, 239, 63, 64, 105, 4, 102, 211, - 3, 43, 180, 109, 69, 210, 168, 47, 199, 3, 231, 17, 41, 201, 253, 197, 66, 155, 36, 12, 34, 61, - 169, 95, 84, 39, 35, 149, 250, 234, 76, 165, 17, 124, 40, 205, 185, 201, 27, 71, 191, 77, 148, - 228, 244, 148, 31, 91, 252, 89, 141, 6, 13, 139, 105, 158, 82, 26, 166, 148, 184, 91, 40, 185, - 45, 214, 150, 78, 230, 134, 109, 250, 24, 78, 249, 49, 197, 186, 141, 6, 36, 32, 3, 11, 190, - 10, 245, 46, 197, 227, 241, 252, 227, 191, 255, 125, 8, 152, 30, 193, 129, 20, 117, 98, 43, - 205, 180, 85, 212, 192, 84, 108, 211, 147, 32, 6, 105, 154, 54, 32, 217, 251, 178, 189, 125, - 44, 74, 148, 158, 166, 35, 31, 32, 123, 202, 155, 237, 245, 244, 162, 130, 75, 66, 176, 19, 4, - 95, 32, 2, 53, 72, 92, 244, 10, 199, 85, 215, 98, 197, 202, 53, 55, 48, 73, 121, 142, 75, 201, - 211, 59, 249, 82, 99, 28, 177, 49, 24, 229, 179, 18, 32, 3, 147, 151, 167, 74, 59, 143, 23, - 251, 79, 191, 28, 36, 70, 115, 138, 125, 47, 234, 176, 10, 181, 87, 6, 92, 201, 241, 192, 251, - 131, 0, 88, 32, 4, 39, 97, 124, 163, 176, 81, 173, 238, 229, 62, 141, 71, 149, 157, 213, 58, - 29, 88, 81, 70, 210, 37, 247, 98, 32, 227, 122, 92, 107, 158, 25, 32, 1, 61, 39, 156, 131, 15, - 116, 96, 118, 150, 228, 16, 100, 173, 143, 116, 225, 32, 132, 100, 64, 218, 62, 42, 82, 24, - 237, 250, 224, 123, 138, 97, 32, 2, 146, 189, 233, 22, 145, 97, 183, 76, 47, 228, 86, 179, 24, - 44, 22, 187, 234, 165, 124, 212, 168, 28, 48, 170, 172, 113, 149, 59, 111, 126, 0, 32, 1, 73, - 94, 244, 139, 72, 176, 219, 166, 23, 242, 43, 89, 140, 22, 11, 93, 245, 82, 190, 106, 84, 14, - 24, 85, 86, 56, 202, 157, 183, 191, 0, 32, 7, 49, 84, 83, 237, 209, 73, 126, 221, 105, 98, 146, - 151, 69, 38, 138, 147, 197, 172, 158, 154, 130, 67, 143, 205, 176, 10, 185, 201, 66, 199, 20, - 32, 1, 75, 213, 109, 3, 8, 2, 241, 101, 42, 61, 134, 159, 48, 52, 142, 224, 44, 155, 89, 243, - 73, 37, 137, 11, 64, 126, 128, 131, 255, 70, 42, 32, 1, 104, 35, 95, 92, 228, 27, 175, 98, 140, - 205, 91, 31, 157, 252, 165, 220, 105, 251, 241, 140, 219, 12, 161, 65, 197, 62, 110, 124, 61, - 193, 122, 32, 1, 149, 72, 216, 225, 106, 116, 178, 76, 86, 77, 33, 43, 180, 163, 197, 44, 142, - 52, 198, 3, 206, 173, 228, 211, 204, 13, 227, 175, 28, 97, 231, 32, 2, 232, 98, 147, 59, 174, - 70, 149, 38, 167, 15, 131, 123, 149, 113, 85, 110, 221, 121, 170, 84, 232, 24, 79, 75, 130, 8, - 99, 192, 32, 16, 235, 32, 2, 115, 182, 7, 186, 57, 90, 222, 26, 175, 88, 28, 210, 226, 219, - 114, 205, 112, 174, 240, 165, 47, 13, 207, 147, 229, 120, 162, 31, 51, 215, 163, 32, 3, 198, - 127, 221, 133, 73, 158, 119, 151, 181, 21, 139, 83, 240, 137, 62, 75, 131, 90, 183, 183, 239, - 195, 107, 108, 247, 170, 165, 138, 0, 211, 101, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 6, 148, 216, 207, 2, 3, 139, 221, - 191, 137, 87, 81, 23, 179, 133, 145, 206, 30, 137, 32, 236, 3, 210, 246, 126, 171, 104, 57, - 139, 240, 51, 41, 32, 4, 36, 244, 60, 5, 202, 242, 129, 217, 68, 10, 21, 74, 144, 101, 2, 160, - 60, 17, 219, 171, 167, 13, 137, 161, 241, 186, 130, 225, 71, 234, 214, 32, 1, 120, 99, 212, 90, - 47, 150, 255, 235, 159, 211, 99, 64, 152, 122, 210, 217, 205, 190, 167, 6, 216, 51, 109, 66, - 132, 35, 200, 191, 124, 240, 108, 32, 0, 85, 76, 196, 128, 0, 235, 158, 110, 54, 224, 100, 184, - 2, 249, 168, 88, 22, 127, 135, 187, 9, 7, 183, 255, 194, 35, 136, 175, 95, 212, 5, 32, 6, 232, - 9, 192, 228, 11, 65, 179, 232, 87, 242, 201, 109, 203, 41, 107, 35, 226, 68, 234, 223, 245, 93, - 27, 222, 156, 178, 238, 17, 166, 94, 17, 32, 4, 211, 244, 238, 153, 155, 124, 251, 84, 27, 24, - 181, 30, 62, 39, 10, 205, 80, 36, 200, 169, 126, 135, 91, 34, 243, 59, 138, 71, 139, 81, 122, - 32, 4, 249, 127, 248, 99, 200, 239, 97, 58, 47, 101, 113, 234, 47, 153, 251, 99, 195, 238, 58, - 209, 62, 79, 82, 158, 246, 104, 189, 122, 227, 79, 141, 32, 4, 216, 135, 181, 159, 147, 233, - 118, 112, 189, 56, 66, 185, 24, 223, 247, 190, 251, 107, 14, 55, 253, 118, 20, 103, 13, 146, - 118, 84, 217, 114, 68, 32, 3, 55, 72, 118, 32, 193, 11, 90, 79, 171, 240, 210, 127, 212, 50, - 136, 202, 240, 242, 91, 53, 27, 176, 114, 48, 235, 25, 155, 191, 85, 215, 179, 32, 7, 60, 186, - 164, 44, 164, 3, 52, 158, 62, 202, 42, 164, 34, 156, 39, 97, 241, 242, 57, 98, 16, 0, 46, 234, - 50, 242, 103, 36, 5, 42, 220, 32, 3, 54, 237, 18, 222, 139, 112, 60, 46, 63, 108, 110, 174, 47, - 57, 160, 216, 32, 41, 246, 139, 129, 182, 57, 27, 28, 201, 29, 194, 2, 3, 166, 32, 1, 231, 166, - 140, 238, 19, 197, 108, 196, 234, 26, 189, 31, 111, 60, 13, 157, 180, 28, 203, 124, 18, 218, - 112, 151, 28, 237, 157, 142, 74, 234, 145, 32, 1, 222, 126, 43, 229, 237, 144, 32, 71, 228, - 134, 109, 56, 4, 9, 182, 82, 226, 22, 57, 57, 96, 237, 189, 201, 188, 250, 143, 228, 168, 242, - 134, 32, 3, 84, 196, 181, 38, 231, 130, 57, 41, 14, 217, 197, 28, 205, 198, 192, 14, 222, 219, - 165, 223, 64, 96, 139, 249, 108, 125, 122, 1, 206, 33, 168, 32, 4, 127, 37, 41, 40, 69, 83, - 115, 128, 57, 163, 238, 214, 120, 89, 132, 32, 75, 86, 205, 195, 101, 38, 142, 53, 46, 0, 96, - 56, 121, 245, 198, 32, 3, 131, 244, 217, 63, 35, 70, 189, 36, 185, 108, 151, 105, 132, 254, - 196, 196, 113, 57, 67, 7, 30, 248, 110, 177, 121, 138, 20, 4, 224, 60, 97, 32, 1, 53, 24, 227, - 221, 240, 49, 77, 110, 222, 152, 144, 32, 81, 121, 130, 16, 67, 138, 39, 2, 205, 235, 235, 21, - 253, 57, 139, 32, 242, 128, 248, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 254, 239, 253, 240, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 239, 255, 225, 36, 32, 1, 95, 221, 207, 191, 219, 55, 97, 99, 251, 192, 205, 3, 114, 74, - 92, 4, 36, 106, 253, 169, 75, 241, 254, 245, 24, 64, 21, 99, 212, 158, 109, 32, 0, 168, 155, - 93, 165, 62, 251, 124, 91, 82, 159, 226, 74, 255, 187, 119, 61, 168, 110, 222, 26, 135, 252, - 101, 233, 211, 126, 44, 147, 141, 111, 220, 32, 5, 244, 149, 55, 66, 246, 81, 145, 22, 178, - 191, 85, 183, 29, 228, 251, 146, 44, 196, 156, 226, 189, 245, 232, 111, 128, 226, 94, 134, 161, - 94, 215, 32, 0, 124, 211, 136, 212, 237, 132, 89, 190, 157, 73, 240, 3, 81, 253, 127, 143, 159, - 153, 111, 44, 228, 127, 176, 196, 153, 73, 204, 148, 222, 43, 243, 32, 2, 41, 134, 84, 204, 74, - 209, 68, 173, 234, 92, 215, 26, 246, 3, 176, 88, 94, 125, 120, 106, 171, 106, 25, 227, 153, - 146, 168, 108, 130, 87, 102, 32, 1, 167, 29, 172, 208, 222, 255, 9, 85, 21, 140, 71, 76, 106, - 241, 229, 213, 23, 86, 218, 165, 151, 6, 14, 227, 167, 2, 244, 194, 160, 109, 207, 32, 4, 255, - 123, 163, 6, 56, 129, 72, 164, 9, 96, 223, 95, 8, 21, 6, 147, 165, 46, 5, 220, 82, 218, 95, 65, - 51, 106, 29, 31, 60, 158, 170, 32, 2, 127, 189, 209, 131, 28, 64, 164, 82, 4, 176, 111, 175, - 132, 10, 131, 73, 210, 151, 2, 238, 41, 109, 47, 160, 153, 181, 14, 143, 158, 79, 85, 32, 0, - 180, 83, 227, 153, 248, 117, 67, 240, 124, 101, 20, 41, 99, 46, 170, 12, 1, 89, 22, 76, 105, - 220, 131, 35, 133, 36, 67, 140, 78, 156, 196, 32, 7, 103, 245, 221, 83, 165, 245, 206, 121, - 240, 5, 30, 33, 100, 156, 91, 148, 19, 184, 179, 147, 241, 121, 17, 38, 224, 246, 100, 155, - 166, 20, 195, 32, 5, 78, 64, 59, 220, 248, 56, 206, 236, 165, 189, 155, 85, 14, 110, 172, 58, - 48, 178, 228, 63, 118, 241, 158, 35, 122, 56, 31, 125, 113, 108, 125, 32, 4, 226, 254, 215, - 177, 61, 91, 140, 61, 196, 148, 104, 63, 127, 119, 114, 0, 4, 21, 91, 215, 147, 158, 175, 142, - 12, 235, 253, 25, 228, 146, 119, 32, 0, 49, 226, 144, 38, 216, 177, 200, 182, 133, 44, 17, 153, - 251, 225, 40, 140, 62, 69, 147, 216, 223, 181, 69, 77, 206, 246, 108, 141, 251, 71, 52, 32, 2, - 120, 169, 191, 163, 21, 134, 50, 114, 57, 38, 164, 59, 95, 233, 84, 82, 198, 149, 156, 22, 245, - 226, 237, 44, 80, 87, 238, 10, 34, 252, 194, 32, 4, 176, 201, 218, 169, 245, 24, 19, 128, 150, - 160, 46, 111, 81, 30, 18, 144, 123, 88, 98, 224, 208, 23, 97, 233, 96, 117, 179, 73, 144, 243, - 123, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 32, 6, 173, 49, 21, 158, 122, 84, 204, 189, 120, 170, 50, 50, 9, 148, 55, 132, 167, - 68, 143, 159, 255, 247, 71, 172, 115, 243, 3, 155, 196, 167, 138, 32, 4, 217, 76, 180, 139, - 176, 217, 11, 243, 207, 252, 154, 192, 137, 41, 111, 57, 90, 135, 71, 231, 114, 174, 44, 36, - 171, 238, 221, 46, 44, 4, 212, 32, 3, 104, 235, 170, 158, 191, 37, 78, 41, 40, 108, 103, 133, - 159, 242, 130, 224, 242, 191, 52, 213, 37, 102, 143, 126, 151, 189, 193, 84, 210, 197, 175, 32, - 3, 89, 248, 104, 149, 197, 48, 181, 235, 34, 205, 235, 12, 240, 143, 145, 205, 250, 4, 236, 30, - 10, 92, 101, 252, 193, 159, 143, 180, 230, 6, 225, 32, 5, 136, 251, 4, 187, 109, 185, 93, 122, - 224, 220, 126, 200, 40, 109, 217, 39, 36, 21, 190, 240, 232, 250, 196, 91, 188, 89, 172, 80, - 121, 251, 197, 32, 1, 111, 83, 106, 97, 202, 254, 209, 6, 173, 240, 252, 164, 82, 7, 224, 97, - 43, 170, 100, 11, 116, 202, 231, 251, 250, 128, 242, 226, 82, 136, 48, 32, 4, 153, 150, 239, - 193, 196, 177, 132, 172, 200, 165, 223, 53, 24, 235, 76, 250, 245, 197, 80, 180, 170, 139, 2, - 254, 136, 131, 70, 46, 37, 49, 231, 32, 0, 86, 74, 64, 98, 112, 228, 198, 26, 65, 236, 91, 39, - 36, 6, 154, 69, 20, 124, 58, 213, 99, 176, 37, 229, 246, 236, 43, 208, 15, 23, 156, 32, 4, 103, - 120, 243, 154, 150, 52, 17, 243, 253, 106, 159, 106, 191, 121, 159, 177, 200, 92, 26, 253, 67, - 248, 230, 35, 16, 176, 38, 229, 139, 47, 217, 32, 6, 222, 171, 49, 136, 19, 201, 120, 131, 213, - 222, 1, 253, 81, 182, 155, 115, 141, 254, 169, 37, 142, 182, 74, 161, 16, 21, 243, 201, 239, - 166, 237, 32, 3, 194, 35, 118, 25, 203, 239, 88, 140, 107, 15, 136, 189, 11, 41, 196, 36, 17, - 147, 104, 53, 45, 41, 248, 175, 68, 242, 183, 160, 235, 76, 182, 32, 5, 17, 199, 242, 192, 147, - 65, 0, 240, 120, 32, 247, 227, 118, 152, 107, 93, 4, 25, 227, 81, 107, 67, 188, 206, 52, 204, - 225, 191, 11, 196, 128, 32, 6, 186, 164, 209, 236, 178, 225, 233, 6, 195, 82, 146, 237, 249, - 168, 60, 158, 33, 10, 76, 196, 40, 127, 22, 31, 165, 117, 101, 239, 29, 7, 76, 32, 1, 226, 126, - 209, 63, 20, 29, 90, 89, 251, 20, 179, 140, 218, 217, 69, 48, 115, 38, 193, 235, 196, 169, 22, - 196, 204, 232, 239, 3, 239, 92, 41, 32, 0, 5, 15, 121, 103, 3, 117, 142, 239, 173, 234, 237, - 79, 27, 214, 108, 5, 207, 244, 232, 195, 236, 211, 88, 66, 32, 141, 141, 132, 196, 193, 86, 32, - 7, 158, 68, 239, 145, 204, 224, 145, 205, 170, 63, 191, 196, 153, 22, 160, 11, 146, 44, 74, - 225, 60, 110, 38, 49, 152, 149, 191, 244, 145, 10, 194, 32, 5, 173, 0, 28, 169, 187, 187, 96, - 93, 152, 117, 4, 157, 177, 36, 34, 201, 16, 52, 49, 208, 136, 121, 107, 138, 228, 95, 165, 135, - 26, 69, 47, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 254, 239, 253, 240, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 239, 255, 225, 1, 8, - 122, 107, 46, 123, 111, 34, 21, 230, 57, 88, 106, 172, 247, 89, 5, 135, 225, 209, 37, 8, 43, - 63, 196, 70, 132, 198, 92, 63, 41, 32, 3, 37, 79, 82, 161, 150, 171, 6, 235, 166, 230, 28, 75, - 255, 199, 173, 5, 64, 127, 243, 17, 216, 246, 121, 201, 242, 72, 71, 190, 113, 0, 94, 74, 254, - 1, 190, 5, 61, 96, 250, 121, 19, 39, 152, 157, 244, 3, 124, 85, 63, 93, 4, 173, 148, 68, 213, - 168, 183, 190, 219, 147, 115, 143, 161, 69, 180, 197, 73, 177, 234, 208, 27, 60, 41, 216, 97, - 7, 238, 84, 243, 112, 223, 124, 198, 87, 62, 100, 1, 182, 121, 114, 68, 57, 96, 130, 251, 242, - 178, 56, 157, 104, 149, 253, 46, 114, 210, 221, 95, 187, 154, 66, 26, 149, 116, 247, 66, 212, - 37, 90, 22, 88, 55, 4, 71, 127, 215, 53, 53, 16, 36, 165, 107, 85, 164, 80, 243, 242, 36, 235, - 226, 199, 191, 219, 14, 217, 84, 59, 78, 176, 165, 80, 100, 218, 54, 140, 125, 197, 249, 99, - 247, 17, 71, 160, 180, 121, 49, 249, 172, 16, 189, 110, 38, 119, 42, 116, 95, 138, 195, 26, - 201, 251, 87, 172, 17, 108, 168, 101, 136, 252, 118, 147, 242, 33, 11, 16, 200, 158, 124, 254, - 165, 5, 73, 12, 53, 221, 137, 122, 171, 78, 203, 75, 123, 4, 181, 50, 42, 37, 32, 13, 234, 176, - 114, 190, 190, 94, 157, 8, 119, 121, 78, 36, 5, 32, 246, 204, 151, 153, 10, 5, 249, 73, 32, - 144, 122, 132, 32, 190, 22, 176, 120, 255, 129, 202, 116, 185, 1, 55, 125, 178, 79, 82, 161, - 150, 171, 6, 235, 166, 230, 28, 75, 255, 199, 173, 5, 64, 127, 243, 17, 216, 246, 121, 201, - 242, 72, 71, 190, 113, 0, 94, 74, 254, 1, 190, 5, 61, 96, 250, 121, 19, 39, 152, 157, 244, 3, - 124, 85, 63, 93, 4, 173, 148, 68, 213, 168, 183, 190, 219, 147, 115, 143, 161, 69, 180, 197, - 73, 177, 234, 208, 27, 60, 41, 216, 97, 7, 238, 84, 243, 112, 223, 124, 198, 87, 62, 100, 1, - 182, 121, 114, 68, 57, 96, 130, 251, 242, 178, 56, 157, 104, 149, 253, 46, 114, 210, 221, 95, - 187, 154, 66, 26, 149, 116, 247, 66, 212, 37, 90, 22, 88, 55, 4, 71, 127, 215, 53, 53, 16, 36, - 165, 107, 85, 164, 80, 243, 242, 36, 235, 226, 199, 191, 219, 14, 217, 84, 59, 78, 176, 165, - 80, 100, 218, 54, 140, 125, 197, 249, 99, 247, 17, 71, 160, 180, 121, 49, 249, 172, 16, 189, - 110, 38, 119, 42, 116, 95, 138, 195, 26, 201, 251, 87, 172, 17, 108, 168, 101, 136, 252, 118, - 147, 242, 33, 11, 16, 200, 158, 124, 254, 165, 5, 73, 12, 53, 221, 137, 122, 171, 78, 203, 75, - 123, 4, 181, 50, 42, 37, 32, 13, 234, 176, 114, 190, 190, 94, 157, 23, 32, 2, 185, 190, 201, - 81, 118, 127, 96, 227, 30, 92, 42, 34, 163, 3, 82, 215, 27, 61, 147, 164, 148, 214, 45, 15, 93, - 249, 51, 219, 250, 115, 162, 32, 7, 41, 187, 255, 90, 251, 72, 136, 90, 235, 48, 9, 216, 9, 78, - 76, 17, 47, 221, 89, 51, 162, 235, 172, 239, 223, 131, 112, 12, 195, 222, 159, 32, 7, 41, 187, - 255, 90, 251, 72, 136, 90, 235, 48, 9, 216, 9, 78, 76, 17, 47, 221, 89, 51, 162, 235, 172, 239, - 223, 131, 112, 12, 195, 222, 159, 32, 7, 41, 187, 255, 90, 251, 72, 136, 90, 235, 48, 9, 216, - 9, 78, 76, 17, 47, 221, 89, 51, 162, 235, 172, 239, 223, 131, 112, 12, 195, 222, 159, 32, 4, - 25, 60, 113, 191, 207, 181, 53, 117, 122, 157, 0, 52, 14, 179, 224, 96, 126, 206, 249, 137, - 120, 223, 79, 77, 70, 102, 148, 246, 30, 58, 59, 32, 0, 13, 140, 11, 79, 101, 213, 145, 52, - 151, 147, 74, 78, 103, 93, 96, 173, 180, 60, 14, 117, 196, 252, 7, 85, 187, 0, 72, 233, 241, - 227, 226, 32, 5, 73, 104, 77, 54, 58, 127, 149, 22, 14, 148, 198, 175, 42, 217, 184, 24, 217, - 191, 17, 201, 39, 5, 212, 245, 108, 51, 110, 191, 153, 243, 73, 32, 2, 19, 137, 96, 155, 213, - 247, 87, 65, 5, 174, 150, 54, 6, 243, 229, 50, 214, 13, 128, 243, 254, 241, 107, 94, 56, 172, - 117, 35, 224, 76, 237, 32, 7, 165, 244, 153, 74, 91, 203, 107, 64, 211, 140, 180, 235, 183, 23, - 25, 98, 144, 119, 65, 0, 11, 136, 213, 221, 77, 186, 231, 81, 54, 204, 250, 32, 4, 234, 254, - 109, 135, 47, 223, 117, 85, 66, 213, 205, 86, 115, 126, 131, 201, 76, 195, 96, 235, 238, 108, - 170, 120, 240, 43, 149, 170, 111, 0, 202, 32, 3, 108, 248, 59, 224, 216, 59, 170, 178, 81, 36, - 101, 253, 115, 81, 14, 17, 134, 248, 147, 250, 14, 134, 171, 69, 10, 197, 67, 112, 96, 26, 248, - 32, 6, 11, 203, 39, 1, 5, 246, 221, 26, 247, 230, 248, 242, 187, 79, 151, 83, 135, 41, 139, 29, - 158, 127, 26, 249, 133, 73, 37, 39, 95, 41, 201, 32, 0, 245, 100, 132, 184, 51, 39, 115, 169, - 27, 16, 178, 240, 215, 220, 85, 146, 222, 3, 48, 155, 249, 104, 95, 142, 12, 146, 91, 23, 143, - 224, 32, 32, 5, 136, 91, 212, 33, 174, 9, 235, 179, 25, 47, 15, 159, 1, 199, 174, 64, 153, 78, - 210, 20, 183, 139, 87, 134, 132, 0, 77, 92, 31, 145, 68, 32, 4, 79, 182, 21, 112, 215, 33, 13, - 211, 20, 53, 56, 100, 79, 14, 49, 52, 108, 154, 163, 96, 203, 186, 242, 206, 132, 194, 83, 204, - 125, 206, 119, 32, 2, 47, 144, 43, 30, 233, 166, 165, 0, 216, 53, 137, 49, 126, 40, 117, 130, - 187, 14, 197, 190, 84, 5, 54, 119, 243, 71, 96, 254, 84, 174, 78, 32, 5, 172, 2, 122, 225, 228, - 225, 136, 13, 98, 203, 118, 42, 130, 102, 124, 29, 193, 182, 209, 61, 122, 87, 168, 75, 146, - 115, 225, 201, 185, 209, 185, 32, 2, 29, 234, 213, 87, 181, 6, 132, 210, 24, 41, 25, 13, 46, - 248, 241, 45, 101, 13, 194, 102, 214, 0, 251, 58, 130, 37, 67, 216, 247, 28, 192, 32, 4, 85, - 26, 129, 216, 192, 23, 218, 104, 224, 233, 37, 158, 65, 139, 21, 169, 239, 82, 54, 103, 184, - 61, 123, 239, 22, 53, 51, 25, 203, 56, 10, 32, 1, 197, 88, 69, 30, 42, 29, 232, 20, 113, 239, - 94, 203, 74, 129, 148, 18, 136, 8, 228, 174, 19, 89, 19, 99, 143, 33, 65, 121, 209, 186, 64, - 32, 1, 40, 249, 95, 107, 238, 241, 61, 121, 0, 251, 76, 248, 241, 141, 199, 14, 252, 192, 174, - 99, 252, 21, 125, 236, 237, 205, 31, 17, 122, 136, 65, 32, 3, 58, 205, 98, 230, 49, 144, 14, - 123, 71, 11, 32, 127, 229, 127, 214, 174, 17, 86, 204, 202, 214, 91, 189, 188, 173, 197, 42, - 131, 68, 53, 158, 32, 2, 148, 100, 44, 115, 248, 179, 128, 111, 48, 110, 86, 181, 103, 101, - 153, 25, 42, 122, 126, 63, 38, 39, 182, 68, 109, 62, 203, 152, 1, 182, 93, 23, 32, 0, 177, 112, - 221, 230, 64, 11, 164, 35, 3, 8, 65, 218, 108, 182, 90, 245, 190, 38, 24, 154, 229, 253, 43, - 142, 0, 130, 222, 131, 163, 199, 191, 32, 5, 253, 167, 130, 154, 76, 153, 7, 23, 68, 51, 154, - 166, 154, 10, 20, 9, 65, 61, 135, 73, 47, 129, 187, 29, 120, 18, 32, 204, 8, 228, 138, 32, 5, - 253, 167, 130, 154, 76, 153, 7, 23, 68, 51, 154, 166, 154, 10, 20, 9, 65, 61, 135, 73, 47, 129, - 187, 29, 120, 18, 32, 204, 8, 228, 138, 32, 5, 253, 167, 130, 154, 76, 153, 7, 23, 68, 51, 154, - 166, 154, 10, 20, 9, 65, 61, 135, 73, 47, 129, 187, 29, 120, 18, 32, 204, 8, 228, 138, 32, 4, - 204, 242, 235, 254, 170, 58, 180, 146, 175, 33, 98, 116, 149, 249, 198, 214, 176, 105, 176, 63, - 251, 152, 191, 49, 93, 107, 35, 141, 179, 214, 198, 32, 5, 88, 0, 73, 35, 11, 51, 169, 127, - 189, 228, 4, 80, 200, 106, 181, 180, 224, 42, 189, 206, 155, 93, 50, 70, 78, 17, 221, 63, 122, - 64, 87, 32, 0, 65, 187, 83, 167, 237, 79, 88, 148, 50, 180, 230, 202, 144, 62, 23, 152, 26, - 148, 150, 210, 159, 60, 162, 94, 88, 128, 241, 0, 62, 177, 87, 32, 6, 202, 120, 8, 33, 88, 198, - 76, 203, 241, 179, 83, 210, 208, 13, 97, 224, 119, 3, 192, 245, 59, 54, 140, 117, 59, 97, 76, - 216, 121, 67, 255, 32, 1, 218, 169, 233, 62, 98, 15, 85, 98, 119, 31, 162, 109, 182, 171, 175, - 155, 59, 166, 160, 232, 76, 98, 188, 118, 125, 117, 24, 130, 227, 157, 116, 32, 2, 10, 131, - 133, 220, 5, 113, 0, 251, 247, 79, 249, 46, 174, 45, 4, 106, 227, 192, 154, 202, 126, 111, 12, - 70, 49, 42, 138, 182, 129, 119, 206, 32, 2, 177, 236, 177, 120, 193, 106, 63, 83, 255, 158, 47, - 96, 53, 228, 187, 29, 82, 48, 98, 144, 58, 32, 181, 93, 166, 99, 160, 16, 147, 126, 205, 32, 3, - 124, 158, 193, 250, 134, 70, 161, 37, 180, 66, 215, 240, 91, 103, 81, 55, 119, 151, 240, 122, - 49, 152, 253, 21, 157, 194, 118, 204, 154, 50, 210, 32, 1, 130, 58, 19, 35, 168, 37, 175, 91, - 187, 4, 137, 46, 126, 147, 175, 240, 122, 106, 145, 247, 4, 6, 28, 219, 110, 6, 89, 106, 171, - 122, 46, 32, 7, 46, 219, 171, 86, 142, 56, 253, 17, 210, 82, 40, 178, 123, 251, 223, 224, 181, - 1, 51, 161, 211, 168, 142, 233, 27, 44, 173, 149, 68, 196, 148, 32, 2, 195, 209, 107, 42, 33, - 250, 250, 220, 20, 186, 72, 57, 139, 57, 243, 166, 239, 195, 172, 209, 146, 1, 198, 238, 81, - 17, 120, 140, 123, 53, 66, 32, 1, 89, 244, 9, 149, 65, 28, 145, 169, 192, 160, 50, 161, 195, - 170, 236, 161, 142, 62, 193, 177, 63, 71, 153, 208, 64, 177, 255, 91, 82, 10, 156, 32, 4, 243, - 116, 187, 26, 108, 113, 71, 86, 1, 14, 120, 31, 168, 141, 184, 220, 29, 214, 174, 245, 90, 149, - 208, 226, 238, 117, 214, 233, 212, 252, 241, 32, 7, 229, 192, 89, 78, 105, 2, 255, 174, 236, - 100, 177, 115, 255, 9, 182, 190, 4, 53, 118, 48, 193, 8, 237, 45, 177, 217, 202, 9, 79, 121, 7, - 32, 5, 90, 40, 57, 46, 10, 89, 140, 53, 199, 232, 129, 134, 25, 222, 218, 39, 42, 143, 83, 161, - 44, 6, 191, 133, 174, 201, 176, 207, 148, 97, 131, 32, 7, 132, 111, 173, 88, 120, 117, 200, - 143, 251, 234, 181, 34, 111, 125, 83, 133, 144, 97, 13, 6, 68, 53, 15, 112, 15, 45, 196, 240, - 246, 250, 24, 32, 7, 15, 67, 4, 99, 90, 199, 22, 114, 244, 176, 34, 72, 8, 195, 232, 234, 216, - 152, 130, 213, 75, 146, 49, 248, 226, 79, 226, 240, 28, 170, 55, 32, 6, 7, 240, 50, 223, 56, - 217, 122, 130, 10, 217, 101, 58, 143, 84, 234, 212, 3, 132, 11, 197, 138, 192, 188, 30, 131, - 169, 7, 245, 175, 161, 162, 32, 6, 232, 158, 56, 95, 230, 63, 244, 175, 237, 55, 162, 218, 226, - 159, 76, 184, 15, 30, 11, 204, 189, 241, 87, 181, 136, 203, 175, 53, 110, 126, 67, 1, 0, 32, 7, - 255, 255, 255, 255, 255, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 32, 7, 255, 255, 255, 255, 255, - 185, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 251, 225, 32, 7, 255, 255, 255, 255, 255, 185, 240, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 251, 225, 32, 7, 255, 255, 255, 255, 255, 245, 112, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 32, 7, 255, 255, - 255, 255, 255, 103, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 247, 1, 1, 251, 251, 127, 1, 251, 1, 128, 2, 2, 1, 5, - 3, 33, 72, 32, 32, 7, 255, 255, 255, 255, 255, 200, 208, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 193, 32, 6, 47, - 252, 208, 5, 81, 69, 218, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 246, 251, 47, 255, 208, 0, 80, 19, 43, 32, 7, 255, 255, 255, 255, 255, 194, 112, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 252, 97, 32, 0, 0, 0, 0, 0, 0, 21, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 64, 32, 7, 255, 255, 255, 255, 255, 209, 80, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 65, 32, 7, - 144, 1, 16, 1, 16, 151, 69, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 251, 238, 144, 0, 16, 0, 16, 8, 230, 32, 7, 255, 255, 255, 255, 255, 243, 80, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 65, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, 255, 255, 255, 224, 48, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 33, 32, 2, - 47, 252, 208, 1, 17, 35, 65, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 247, 255, 47, 255, 208, 0, 16, 17, 34, 32, 7, 255, 255, 255, 255, 255, 213, 144, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 253, 129, 32, 1, 176, 7, 112, 1, 17, 69, 82, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 246, 254, 176, 0, 112, 0, 16, 19, 35, 32, 7, 255, 255, 255, - 255, 255, 192, 80, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 252, 65, 32, 7, 144, 1, 16, 1, 16, 151, 69, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 251, 238, 144, 0, 16, 0, 16, 8, - 230, 32, 7, 255, 255, 255, 255, 255, 205, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 1, 32, 1, 176, 7, 112, 1, 17, - 69, 82, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 254, - 176, 0, 112, 0, 16, 19, 35, 32, 7, 255, 255, 255, 255, 255, 251, 208, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 193, - 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 32, 7, 255, 255, 255, 255, 255, 230, 144, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 129, 32, 7, 255, 255, - 255, 255, 255, 245, 112, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 32, 7, 255, 255, 255, 255, 255, 249, 176, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 161, 32, 6, 111, 252, 207, 252, 208, 76, 229, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 253, 223, 111, 255, 207, 255, 208, 4, 134, 32, 7, 255, - 255, 255, 255, 255, 196, 144, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 129, 32, 6, 111, 252, 207, 252, 208, 76, 229, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 223, 111, 255, - 207, 255, 208, 4, 134, 32, 7, 255, 255, 255, 255, 255, 232, 176, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 161, 32, - 2, 47, 252, 208, 1, 17, 69, 65, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 246, 255, 47, 255, 208, 0, 16, 19, 34, 32, 7, 255, 255, 255, 255, 255, 226, 80, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 254, 65, 32, 7, 255, 255, 255, 255, 255, 245, 112, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 32, 7, - 255, 255, 255, 255, 255, 198, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 161, 32, 0, 0, 0, 0, 0, 0, 2, 32, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 32, 7, 255, 255, 255, 255, - 255, 222, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 254, 1, 32, 7, 255, 255, 255, 255, 255, 228, 112, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 254, 97, 32, 7, 255, 255, 255, 255, 255, 188, 16, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 252, 1, 32, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 7, 255, 255, - 255, 255, 255, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 32, 0, 15, 252, 208, 1, 16, 20, 81, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 15, 255, 208, 0, 16, - 1, 50, 32, 7, 255, 255, 255, 255, 255, 241, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33, 32, 2, 47, 252, 208, - 1, 17, 69, 65, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, - 255, 47, 255, 208, 0, 16, 19, 34, 32, 7, 255, 255, 255, 255, 255, 219, 240, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, - 225, 32, 7, 144, 1, 16, 1, 16, 151, 69, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 251, 238, 144, 0, 16, 0, 16, 8, 230, 32, 7, 255, 255, 255, 255, 255, 217, - 208, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 253, 193, 32, 0, 15, 252, 208, 1, 16, 15, 137, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 191, 15, 255, 208, 0, 16, 0, 234, 32, 7, - 255, 255, 255, 255, 255, 211, 112, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 97, 32, 1, 176, 7, 112, 1, 17, 69, 82, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 246, 254, 176, 0, - 112, 0, 16, 19, 35, 32, 7, 255, 255, 255, 255, 255, 234, 208, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 193, 32, - 7, 255, 255, 255, 255, 255, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 32, 7, 255, 255, 255, 255, - 255, 215, 176, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 253, 161, 32, 7, 255, 255, 255, 255, 255, 245, 112, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 97, 32, 7, 255, 255, 255, 255, 255, 228, 112, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 254, 97, 32, 6, 111, 252, - 207, 252, 208, 76, 229, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 253, 223, 111, 255, 207, 255, 208, 4, 134, 32, 7, 255, 255, 255, 255, 255, 202, 240, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 252, 225, 32, 0, 176, 3, 48, 1, 17, 69, 116, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 246, 253, 176, 0, 48, 0, 16, 19, 37, 32, 7, 255, 255, 255, - 255, 255, 247, 144, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 129, 32, 7, 255, 255, 255, 255, 255, 247, 144, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 129, 32, 7, 255, 255, 255, 255, 255, 245, 112, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 97, 32, 0, - 15, 252, 208, 1, 16, 6, 197, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 223, 15, 255, 208, 0, 16, 0, 102, 32, 7, 255, 255, 255, 255, 255, 236, 240, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 254, 225, 32, 2, 47, 252, 208, 1, 17, 69, 65, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 246, 255, 47, 255, 208, 0, 16, 19, 34, 32, 7, 255, 255, 255, - 255, 255, 190, 48, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 252, 33, 32, 7, 255, 255, 255, 255, 255, 185, 240, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 251, 225, 32, 7, 255, 255, 255, 255, 255, 239, 16, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, 32, 7, 255, 255, - 255, 255, 255, 253, 240, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 225, 32, 7, 255, 255, 255, 255, 255, 207, 48, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 253, 33, 32, 5, 176, 7, 112, 9, 145, 69, 235, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 246, 250, 176, 0, 112, 0, 144, 19, 44, 64, -]; diff --git a/provers/groth16/README.md b/provers/groth16/README.md index dae3aeae1..5e48d6b3f 100644 --- a/provers/groth16/README.md +++ b/provers/groth16/README.md @@ -1,3 +1,156 @@ # Lambdaworks Groth16 Prover -An under-optimized implementation of [Groth16](https://eprint.iacr.org/2016/260) protocol. +An under-optimized implementation of [Groth16](https://eprint.iacr.org/2016/260) protocol. To use it with Circom, check the [examples](./circom-adapter/src/README.md). + +## Introduction + +Over the last decade, SNARKs (succinct, non-interactive arguments of knowledge) and STARKs (scalable, transparent arguments of knowledge) have been gaining attention due to their applications in verifiable private computation and scalability of blockchains. + +Groth introduced this [proof system](https://eprint.iacr.org/2016/260.pdf) in 2016 and saw an early application in ZCash. The protocol relies on pairing-friendly elliptic curves, such as BN254, BLS12-381, and BLS12-377 (more later). Its proof size is among the smallest (consisting of only three elliptic curve elements) and fastest to verify. The main drawback is that it needs a trusted setup per program. In other words, we need to regenerate all the parameters whenever we want to prove a new program (or change the original one). + +## Arithmetization + +To prove the execution of a given program, we have to transform it to a SNARK (succinct, non-interactive argument of knowledge) friendly form. One of such forms is arithmetic circuit satisfiability, where one can prove knowledge of a valid circuit assignment. This first step, known as arithmetization, is the program's transformation into an arithmetic circuit or equivalent form. + +## R1CS + +Arithmetic circuits can be expressed equivalently as (quadratic) rank one constraint systems (R1CS), which are systems of equations of the form: +$$(Az)\times (Bz) = Cz$$ +where $A, B, C$ are matrices of size $m + 1$ rows by $n + 1$ columns, $z$ is a (column) vector of size $n + 1$ and $\times$ indicates the componentwise product of the resulting vectors. + +We can alternatively view this compact form as +$\left( \sum_k a_{0k} z_k \right) \left( \sum_k b_{0k} z_k \right) - \left( \sum_k c_{0k} z_k \right) = 0$ +$\left( \sum_k a_{1k} z_k \right) \left( \sum_k b_{1k} z_k \right) - \left( \sum_k c_{1k} z_k \right) = 0$ +$\left( \sum_k a_{2k} z_k \right) \left( \sum_k b_{2k} z_k \right) - \left( \sum_k c_{2k} z_k \right) = 0$ +$\vdots$ +$\left( \sum_k a_{mk} z_k \right) \left( \sum_k b_{mk} z_k \right) - \left( \sum_k c_{mk} z_k \right) = 0$ + +We could express these equations more compactly by using polynomials and prove the solution of the R1CS system more concisely. To this end, we will introduce quadratic arithmetic programs, [QAP](https://vitalik.ca/general/2016/12/10/qap.html). + +## Quadratic Arithmetic Program + +We can interpret each column of the $A$ matrix as evaluations of some polynomial over some suitable domain. This is a common practice in many SNARKs, where we try to encode a vector as a polynomial; see, for example, our [post about STARKs](https://blog.lambdaclass.com/diving-deep-fri/). We sample $D_0 = \{ x_0 , x_1 , ... , x_n \}$ over the finite field and define the polynomial $A_i (x)$ as the polynomial of at most degree $n$ such that $A_i ( x_k ) = a_{ki}$. + +For performance reasons, it is convenient to select as interpolation domain $D_0$ the n-th roots of unity since we can use the Fast Fourier Transform to interpolate. Similarly, we can interpret the columns of $B$ and $C$ as polynomials $B_k (x)$ and $C_k (x)$. Taking advantage of these polynomials, we can express the R1CS system in polynomial form, +$P (x) = \left( \sum_k A_{k} (x) z_k \right) \left( \sum_k B_{k} (x) z_k \right) - \left( \sum_k C_{k} (x) z_k \right)$ + +We can see that if we have a valid solution for the R1CS, the polynomial $P (x)$ evaluates to $0$ over $D_0$ (since we require the polynomial to interpolate the values of the columns of the matrices). Therefore, we can express the condition as +$P (x) = 0$ for $x \in D_0$ +We now introduce the vanishing polynomial over the set $D_0$, $Z_D (x) = \prod_k (x - x_k )$ +So, if the polynomial $P (x)$ evaluates to $0$ over $D_0$, it is divisible by $Z_D (x)$. This can be written as there is some polynomial $h (x)$ such that +$P (x) = h(x) Z_D (x)$ +The degree of the polynomial $h(x)$ is the degree of $P$ minus the degree of $Z_D$. An honest prover should be able to find the resulting quotient and use it to show that he correctly executed the program. + +## Transforming QAP into a zero-knowledge proof + +We need to make some transformation to the above problem if we want to turn it into a zero-knowledge proof. For a more detailed description of this process, see [here](https://www.rareskills.io/post/groth16). We must ensure that the prover cannot cheat and that the verifier cannot learn anything about the private input or witness. One key ingredient is a polynomial commitment scheme (PCS): we can make the prover commit to a given polynomial so that he cannot change it later. One such commitment scheme is the [KZG commitment](https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html), where we use [pairing-friendly elliptic curves](https://static1.squarespace.com/static/5fdbb09f31d71c1227082339/t/5ff394720493bd28278889c6/1609798774687/PairingsForBeginners.pdf) to bind the prover to a polynomial. The scheme's security relies on the hardness of the discrete logarithm problem over the curve. Pairings can be considered an operation that allows a one-time multiplication between points in an elliptic curve. In our case, we will work over type3 III pairings, $\dagger : G_1 \times G_2 \rightarrow G_t$, which have the following nice property (bilinearity): +$(a g_1 ) \dagger (b g_2 ) = (ab) (g_1 \dagger g_2)$ +To commit to a polynomial using KZG, we need to sample a random scalar $\tau$ (which is considered toxic waste and should be forgotten, or we could forge proofs) and generate the following sequence of points in the elliptic curve, whose generator is $g_1$, +$P_0 = g_1$, +$P_1 = \tau g_1$ +$P_2 = \tau^2 g_1$ +$\vdots$ +$P_n = \tau^n g_1$ +Then, given a polynomial $p(x) = a_0 + a_1 x + a_2 x^2 + ... + a_n x^n$ we compute the commitment as +$\mathrm{cm} (p) = a_0 P_0 + a_1 P_1 + ... + a_n P_n$ +which is the same as $\mathrm{cm} (p) = p(\tau) g_1$, that is, hiding the evaluation of $p(x)$ inside the elliptic curve. Because the discrete log problem is hard, we cannot use our knowledge of $g_1$ and $\mathrm{cm} (p)$ to obtain $p(\tau)$. + +To check that the polynomial $p(x)$ evaluates to $v$ at $z$ we can use the fact that +$p(x) - v = (x - z)q(x)$ +where $q(x)$ is the quotient polynomial of the division of $p(x)$ by $x - z$. The prover can produce proof of such evaluation by committing to $q(x)$ using the same trick. Still, the verifier will need some additional information (included in the verifying key), $g_2$ (the generator of the group $G_2$), and $\tau g_2$ (remember, nobody must know $\tau$). Then, using pairings, the verifier can check the evaluation using the points in the elliptic curves, +$(\mathrm{cm} (p) - vg_1 \dagger g_2) = a = p(\tau) (g_1 \dagger g_2)$ +$\mathrm{cm} (q) \dagger (\tau g_2 - z g_2) = b = q(\tau) ( \tau - z)(g_1 \dagger g_2)$ +If $a$ and $b$ are the same, and since $\tau$ is a random point with high probability, we assume that $p(z) = v$ (This depends on the Schwartz-Zippel lemma). + +Remember that we want to prove that the verifier knows some $w$ and a polynomial $h(x)$ of degree $m - 1$ such that if $z= (1, x, w)$, the following condition holds +$\left( \sum_k A_{k} (x) z_k \right) \left( \sum_k B_{k} (x) z_k \right) = \left( \sum_k C_{k} (x) z_k \right) + h(x)Z_D (x)$ + +If we force the prover first to commit to the polynomials $A_k (x)$ and $B_k (x)$ and then produce the quotient polynomial, we have to make sure that he cannot forge $C_k (x)$ to fulfill the previous condition. To do so, we are going to introduce random shifts ($\alpha$ and $\beta$) to the evaluations: +$\mathrm{cm} (\sum A_i z_i ) = \sum (A_i (\tau) z_i) g_1 + \alpha g_1$ +$\mathrm{cm} (\sum B_i z_i) = \sum (B_i (\tau) z_i) g_2 + \beta g_2$ +The $B_i (x)$ are committed to using group $G_2$ so that we can compute the product on the left-hand side through a pairing, +$(\mathrm{cm} (\sum A_i z_i )) \dagger ( \mathrm{cm} (\sum B_i z_i )) = (\sum A_i (\tau) z_i )(\sum B_i (\tau) z_i ) (g_1 \dagger g_2)$ + +Because we introduce these shifts, we need to modify the $C_k$ term accordingly, +$\begin{equation}\left( \alpha + \sum_k A_{k} (x) z_k \right) \left( \beta + \sum_k B_{k} (x) z_k \right) = \\ \alpha \beta + \left( \sum_k (C_{k} (x) + \beta A_k (x) + \alpha B_k (x)) z_k \right) + h(x)Z_D (x) \end{equation}$ +Since the prover cannot know $\alpha$ and $\beta$, we need to provide them hidden as part of the trusted setup, as $\alpha g_1$ and $\beta g_2$, so that we can compute +$(\alpha g_1) \dagger (\beta g_2) = \alpha \beta (g_1 \dagger g_2)$ +so that we can compare this result to the pairing between the shifted $A_i$ and $B_i$. + +Also, since the prover does not have $\alpha$ and $\beta$, he needs to be supplied with all the elements of the form $C_{k} (x) + \beta A_k (x) + \alpha B_k (x)$. However, when we want to calculate the product between these terms and $z$, we must recall that $z$ contains both the public input and the witness. The verifier cannot learn anything about the witness (therefore, the evaluations involving the witness should be provided by the prover). We introduce two additional variables, $\gamma$, and $\delta$, to split the variable $z$ between public input and witness. The first $k$ terms correspond to the public input, and these are encoded as +$K_i^v = \gamma^{- 1} (C_{i} (\tau) + \beta A_i (\tau) + \alpha B_i (\tau)) g_1$ +for $i = 0, 1, 2 ... , k$. For the witness, we have +$K_i^p = \delta^{- 1} (C_{i} (\tau) + \beta A_i (\tau) + \alpha B_i (\tau)) g_1$ +With these new parameters, we get +$\begin{equation}\left( \alpha + \sum_j A_{j} (x) z_j \right) \left( \beta + \sum_j B_{j} (x) z_j \right) = \\ \alpha \beta + \gamma \left( \sum_i^k \gamma^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + \\ +\delta \left( \sum_{j = k + 1}^n \delta^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + h(x)Z_D (x) \end{equation}$ +We can combine the last two terms into one (since they contain all the information that the verifier must not learn) +$D = \left( \sum_{j = k + 1}^n \delta^{- 1} (C_{i} (x) + \beta A_i (x) + \alpha B_i (x)) x_i \right) + h(x)Z_D (x)\delta^{- 1}$ + +Since we want to compute the product $h(x) Z_D(x)$ with the help of one pairing, we can compute the following group elements, +$Z_0 = \delta^{ - 1} Z_D (\tau)$ +$Z_1 = \delta^{ - 1} \tau Z_D (\tau)$ +$Z_2 = \delta^{ - 1} \tau^2 Z_D (\tau)$ +$\vdots$ +$Z_{m - 1} = \delta^{ - 1} \tau^{ m - 1 } Z_D (\tau)$ + +With these changes, the right-hand side of the QAP is the sum of 3 terms: +A constant (related to the random shifts). +A term involving the public input. +A term that contains the secret terms (known only to the prover). + +## Setup + +Groth16 requires sampling five random field elements to generate the proving and verifying key, $t, \alpha, \beta, \gamma, \delta$. These are toxic waste and should be discarded and wholly forgotten once the keys have been generated. + +We will use a pairing-friendly elliptic curve (with type III pairing), with subgroups $G_1$ and $G_2$ of prime order $r$. We will call the generators $g_1$ and $g_2$, respectively. To make notation easier, we will write +$[x]_1 = x g_1$ +$[x]_2 = x g_2$ +to denote points in $G_1$ and $G_2$, where $x g$ means the scalar product of $x$ and the generator of the group (i.e., applying x times the elliptic curve group operation to the generator). We will follow the notation given by [DIZK](https://eprint.iacr.org/2018/691.pdf). First, we compute the following vectors, +$K_i^v (t) = \gamma^{-1} \left( \beta A_i(t) + \alpha B_i (t) + C_i (t)\right)$ +for $i = 0, 1, 2 , ... k$, +$K_i^p (t) = \delta^{-1} \left( \beta A_i(t) + \alpha B_i (t) + C_i (t)\right)$ +for $i = k+1, 1, 2 , ... n$ and +$Z_k (t) = t^k Z_D (t) \delta^{-1}$ +for $k = 0, 1, 2, ... m - 1$. +The proving key consists of the following elements: +1. $[\alpha]_1$ +2. $[\beta]_1$ +3. $[\beta]_2$ +4. $[\delta]_1$ +5. $[\delta]_2$ +6. $[A_0 (t) ]_1, [A_1 (t) ]_1 , ... , [A_n (t) ]_1$ +7. $[B_0 (t) ]_1, [B_1 (t) ]_1 , ... , [B_n (t) ]_1$ +8. $[B_0 (t) ]_2, [B_1 (t) ]_2 , ... , [B_n (t) ]_2$ +9. $[K_{ k + 1 }^p (t)] , [ K_{ k + 2 }^p (t)] , ... , [K_n^p (t)]$ +10. $[Z_0 (t)] , [Z_1 (t)] , ... , [ Z_{ m - 1 } (t)]$ + +The verifying key is much shorter and will contain in addition the value of one pairing because that value is constant: +1. $[\alpha]_1 \dagger [\beta]_2$ +2. $[\gamma]_2$ +3. $[\delta]_2$ +4. $[K_0^v (t)]_1 , [K_1^v (t)]_1 , ... , [K_k^v (t)]_1$ + +## Proof generation + +The prover receives the proving key and knows the polynomials representing the program and the public input, and he wants to prove that he has a witness satisfying that program. First, the prover needs to calculate the quotient polynomial $h(x)$ or, more precisely, its coefficients. The prover has to calculate +$$h(x) = \frac{\sum A_k(x) z_k \sum B_k (x) z_k - \sum C_k (x) z_k}{Z_D (X) }$$ + +The best way to evaluate this quotient is by choosing a domain $D_{ev}$, of size at least the degree of the quotient polynomial plus one and not containing elements from $D_0$ (the interpolation domain) and evaluating numerator and denominator at all the elements of $D_{ev}$. Since we have at least as many evaluations of the polynomial $h (x)$ as its degree plus one, we can reconstruct $h(x)$ via interpolation. In practice, the fastest way to do this is by using the Fast Fourier Transform for evaluation and interpolation. The prover now possesses a vector of coefficients $h_0 , h_1 , h_2 , ... , h_m$. + +To ensure that the proof is zero-knowledge, the prover sample two random scalars, $r$ and $s$. + +The prover can compute the three elements of the proof, $\pi = ([\pi_1 ]_1 , [\pi_2 ]_2 , [\pi_3 ]_1)$ by doing the following calculations, +$[\pi_1 ]_1 = [\alpha]_1 + \sum z_k [A_k (t) ]_1 + r [\delta]_1$ +$[\pi_2 ]_2 = [\beta]_2 + \sum z_k [B_k (t) ]_2 + s[\delta]_2$ +$[\pi_2 ]_1 = [\beta]_1 + \sum z_k [B_k (t) ]_1 + s[\delta]_1$ +$[h(t)z(t)]_1 = \sum h_i [Z_i (t)]_1$ +$[\pi_3 ]_1 = \sum w_i [K_i^p ]_1 + [h(t)z(t)]_1 + s[\pi_1 ]_1 + r [\pi_2 ]_1 - rs [\delta]_1$ + +## Verification + +The verifier has the verifying key, the public input and parses the proof as $[\pi_1 ]_1, [\pi_2 ]_2, [\pi_3 ]_1$ and computes the following: +$[\pi_1 ]_1 \dagger [\pi_2 ]_2 = P_1$ +$[\pi_3 ]_1 \dagger [\delta]_2 + [\alpha]_1 \dagger [\beta]_2 + \left(\sum x_i [K_i^v ]_1 \right) \dagger [\gamma]_2 = P_2$ + +The proof is valid if $P_1$ and $P_2$ coincide. This is equivalent to checking the modified QAP. diff --git a/provers/groth16/circom-adapter/src/README.md b/provers/groth16/circom-adapter/src/README.md index 29fc5fbcf..b0f7253ef 100644 --- a/provers/groth16/circom-adapter/src/README.md +++ b/provers/groth16/circom-adapter/src/README.md @@ -55,7 +55,7 @@ Relative path to a file named **test** will be just **"test"** if it's placed in ```rust // ... -let (w, qap) = circom_to_lambda( +let (qap, w) = circom_to_lambda( &fs::read_to_string("test.r1cs.json").expect("Error reading file"), &fs::read_to_string("witness.json").expect("Error reading file"), ); @@ -65,7 +65,7 @@ As seen, this function returns a Lambdaworks-compatible QAP and the witness assi ```rust fn poseidon_parse_prove_verify() { - let (w, qap) = circom_to_lambda( + let (qap, w) = circom_to_lambda( &fs::read_to_string("test.r1cs.json").expect("Error reading file"), &fs::read_to_string("witness.json").expect("Error reading file"), );