diff --git a/.noir-sync-commit b/.noir-sync-commit index cf76a4efc4b..07ca104bbc0 100644 --- a/.noir-sync-commit +++ b/.noir-sync-commit @@ -1 +1 @@ -c44b62615f1c8ee657eedd82f2b80e2ec76c9078 +130d99125a09110a3ee3e877d88d83b5aa37f369 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b8b46617e26..1b1a9f796fe 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.73.0", + ".": "0.74.0", "yarn-project/cli": "0.35.1", - "yarn-project/aztec": "0.73.0", - "barretenberg": "0.73.0", - "barretenberg/ts": "0.73.0" + "yarn-project/aztec": "0.74.0", + "barretenberg": "0.74.0", + "barretenberg/ts": "0.74.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8de3644ab..a994db0af82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,65 @@ # Changelog +## [0.74.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.73.0...aztec-packages-v0.74.0) (2025-02-04) + + +### ⚠ BREAKING CHANGES + +* staking library ([#11559](https://github.com/AztecProtocol/aztec-packages/issues/11559)) +* time library ([#11542](https://github.com/AztecProtocol/aztec-packages/issues/11542)) + +### Features + +* `u128.ts` accepting string on input ([#11664](https://github.com/AztecProtocol/aztec-packages/issues/11664)) ([bb25992](https://github.com/AztecProtocol/aztec-packages/commit/bb2599240f8cea20c111c1533cff457372e5d458)) +* Add network, better drawer performance ([#11694](https://github.com/AztecProtocol/aztec-packages/issues/11694)) ([1f61822](https://github.com/AztecProtocol/aztec-packages/commit/1f61822e731b6d1cd7295772f54afda54b646514)) +* Skip calculation of partial sums when simulating blobs ([#11257](https://github.com/AztecProtocol/aztec-packages/issues/11257)) ([aca66f7](https://github.com/AztecProtocol/aztec-packages/commit/aca66f7611be2eba774b9d204d732801853cc6a2)) +* Staking library ([#11559](https://github.com/AztecProtocol/aztec-packages/issues/11559)) ([c050320](https://github.com/AztecProtocol/aztec-packages/commit/c0503201f5d25bc559462926222d2ad6bc93479d)) +* Time library ([#11542](https://github.com/AztecProtocol/aztec-packages/issues/11542)) ([3b463f9](https://github.com/AztecProtocol/aztec-packages/commit/3b463f9f9376393c5f781cf2495c6db379308aca)), closes [#11520](https://github.com/AztecProtocol/aztec-packages/issues/11520) +* UltraHonkZK contract ([#11553](https://github.com/AztecProtocol/aztec-packages/issues/11553)) ([a68369f](https://github.com/AztecProtocol/aztec-packages/commit/a68369fd1f12d00e037a2626b2bbc17375054883)) + + +### Bug Fixes + +* Add bootstrap.sh to rebuild_patterns ([#11683](https://github.com/AztecProtocol/aztec-packages/issues/11683)) ([e84a81a](https://github.com/AztecProtocol/aztec-packages/commit/e84a81a556b2059be843e06a7e814cd4fb7f99eb)) +* **archiver:** Do not attempt to decode blob before filtering ([#11668](https://github.com/AztecProtocol/aztec-packages/issues/11668)) ([961cbdd](https://github.com/AztecProtocol/aztec-packages/commit/961cbdd9ee33ce85f9509e690c346988e1a3bccf)) +* Barretenber/stdlib/logic bugs ([#11651](https://github.com/AztecProtocol/aztec-packages/issues/11651)) ([dddab22](https://github.com/AztecProtocol/aztec-packages/commit/dddab22934b3abb798dbf204bccb68b557ee2193)) +* Barretenberg/stdlib/logic bugs (redo) ([#11691](https://github.com/AztecProtocol/aztec-packages/issues/11691)) ([6d0bad7](https://github.com/AztecProtocol/aztec-packages/commit/6d0bad77b2ffdc966462cc333faa9cea4b21f4dc)) +* **docs:** Keys docs update ([#11665](https://github.com/AztecProtocol/aztec-packages/issues/11665)) ([ce3d92c](https://github.com/AztecProtocol/aztec-packages/commit/ce3d92c966cbdd68cc1c8e1e34e1831db5080a34)) +* Remove avm test that was split ([#11719](https://github.com/AztecProtocol/aztec-packages/issues/11719)) ([9dc8158](https://github.com/AztecProtocol/aztec-packages/commit/9dc8158715e69e772b5b08a6556124e1786e9810)) +* Revert "barretenberg/stdlib/logic bugs" ([#11689](https://github.com/AztecProtocol/aztec-packages/issues/11689)) ([b99570d](https://github.com/AztecProtocol/aztec-packages/commit/b99570d416f4c4c59f38e47a8677b476c5c06f0b)) +* Solidity verifier caching ([#11712](https://github.com/AztecProtocol/aztec-packages/issues/11712)) ([2ba1e71](https://github.com/AztecProtocol/aztec-packages/commit/2ba1e7112c4d8052967603ab78c1213cc70b8038)) +* Use eth-execution label ([#11713](https://github.com/AztecProtocol/aztec-packages/issues/11713)) ([d3c31d8](https://github.com/AztecProtocol/aztec-packages/commit/d3c31d887b696865f3df41611fae534e1d89460f)) + + +### Miscellaneous + +* Add tests for gov proposer ([#11633](https://github.com/AztecProtocol/aztec-packages/issues/11633)) ([5c6a48a](https://github.com/AztecProtocol/aztec-packages/commit/5c6a48a251ff4ef25a2efdf90891241df05e8652)), closes [#11681](https://github.com/AztecProtocol/aztec-packages/issues/11681) +* **bb-prover:** Avm test skip and split ([#11717](https://github.com/AztecProtocol/aztec-packages/issues/11717)) ([1778867](https://github.com/AztecProtocol/aztec-packages/commit/177886764a23b9437fdc767726cc7c8533c27f08)) +* Benchmark sha256 number of instructions executed in AVM ([#11253](https://github.com/AztecProtocol/aztec-packages/issues/11253)) ([aaf0d8c](https://github.com/AztecProtocol/aztec-packages/commit/aaf0d8c02b99eb1c037745d54c0859553492c088)) +* Delete MerkleTrees implementation in JS ([#11697](https://github.com/AztecProtocol/aztec-packages/issues/11697)) ([1db7b78](https://github.com/AztecProtocol/aztec-packages/commit/1db7b7845405e1c877da71185566b8495c9469e7)) +* Ensure new kv-store is used on the server ([#11662](https://github.com/AztecProtocol/aztec-packages/issues/11662)) ([aee1420](https://github.com/AztecProtocol/aztec-packages/commit/aee14208a42f9b5b7f9aef4b6e0d92e303a265c1)) +* Field encoding should use `fromString` instead of `fromHexString` ([#11585](https://github.com/AztecProtocol/aztec-packages/issues/11585)) ([43fdbb1](https://github.com/AztecProtocol/aztec-packages/commit/43fdbb17361c3c2e7ab8b2cb79f0c91932a0d56e)), closes [#10331](https://github.com/AztecProtocol/aztec-packages/issues/10331) +* Improve boxes ([#11656](https://github.com/AztecProtocol/aztec-packages/issues/11656)) ([46a3e85](https://github.com/AztecProtocol/aztec-packages/commit/46a3e85c08c930aa2dacb6b20483de1f7926c0ff)) +* Increase node pool count and don't use a release channel ([#11687](https://github.com/AztecProtocol/aztec-packages/issues/11687)) ([65a3f11](https://github.com/AztecProtocol/aztec-packages/commit/65a3f11944975c8cb990a72c8b87df3ed224323c)) +* Mark contracts as pub ([#11241](https://github.com/AztecProtocol/aztec-packages/issues/11241)) ([b168601](https://github.com/AztecProtocol/aztec-packages/commit/b1686016dd91d559cc81a2e250228698e7ff925e)) +* No rbac on kind ([#11714](https://github.com/AztecProtocol/aztec-packages/issues/11714)) ([7a142af](https://github.com/AztecProtocol/aztec-packages/commit/7a142afe387995a40b77d0072987fa6864effd82)) +* Reduce memory requests on prover node ([#11678](https://github.com/AztecProtocol/aztec-packages/issues/11678)) ([a720151](https://github.com/AztecProtocol/aztec-packages/commit/a720151115471722fa46f4f4f8d6a08408659107)) +* Remove profiler cache fallback ([#11680](https://github.com/AztecProtocol/aztec-packages/issues/11680)) ([a305aef](https://github.com/AztecProtocol/aztec-packages/commit/a305aefb8caa0e462f3f7ee535a6dbcadef871da)) +* Remove some templates in templates ([#11698](https://github.com/AztecProtocol/aztec-packages/issues/11698)) ([61614b1](https://github.com/AztecProtocol/aztec-packages/commit/61614b1a0fa4a766b1ad5090a29f92a122511806)) +* Remove unused functions from public side effect trace ([#11600](https://github.com/AztecProtocol/aztec-packages/issues/11600)) ([54e9602](https://github.com/AztecProtocol/aztec-packages/commit/54e960255e43c103170d7caee716fb6a0253f6f4)) +* Replace relative paths to noir-protocol-circuits ([739151e](https://github.com/AztecProtocol/aztec-packages/commit/739151ead0f5e6a9aa421567e9e6329fa7774c13)) +* Replace relative paths to noir-protocol-circuits ([bbd526c](https://github.com/AztecProtocol/aztec-packages/commit/bbd526ce0f53e227f40e9a4ef3c068796aff447b)) +* **sequencer:** Add InvalidArchive to canProposeAtNextEthBlock ignored errors ([#11682](https://github.com/AztecProtocol/aztec-packages/issues/11682)) ([eea4bd3](https://github.com/AztecProtocol/aztec-packages/commit/eea4bd3db21858e67e730324d0610f7c90a12023)) +* **spartan:** Remove hardcoded keys and addresses - derive all from mnemonic ([#11672](https://github.com/AztecProtocol/aztec-packages/issues/11672)) ([65f0e48](https://github.com/AztecProtocol/aztec-packages/commit/65f0e484513734a73e88d78ff490d8c939005eea)) +* Turn off auto-upgrade in node-pools ([#11679](https://github.com/AztecProtocol/aztec-packages/issues/11679)) ([09f98a9](https://github.com/AztecProtocol/aztec-packages/commit/09f98a9f10f18fd48895af40981b670c015f7aa3)) +* Turn on masking in ultra and mega zk + oink clean-up ([#11693](https://github.com/AztecProtocol/aztec-packages/issues/11693)) ([08e96fe](https://github.com/AztecProtocol/aztec-packages/commit/08e96fee292c53afa645a00a8d2689d01e8136d5)) +* Zombienet yaml ([#11705](https://github.com/AztecProtocol/aztec-packages/issues/11705)) ([5e9f12e](https://github.com/AztecProtocol/aztec-packages/commit/5e9f12ebf35d9b26f2aa72c7a89d3d1ddd1f5f24)) + + +### Documentation + +* Update mig notes release version ([#11685](https://github.com/AztecProtocol/aztec-packages/issues/11685)) ([46a30b5](https://github.com/AztecProtocol/aztec-packages/commit/46a30b5a7438b23c64336bc217dcc1686e94b7c4)) + ## [0.73.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.72.1...aztec-packages-v0.73.0) (2025-02-01) @@ -206,7 +266,7 @@ * **avm:** Interactive debugger ([#11477](https://github.com/AztecProtocol/aztec-packages/issues/11477)) ([53e57d3](https://github.com/AztecProtocol/aztec-packages/commit/53e57d3d52dd477714bc984c4a13bc8e5664877e)) * Consensus layer in spartan ([#11105](https://github.com/AztecProtocol/aztec-packages/issues/11105)) ([55dd03c](https://github.com/AztecProtocol/aztec-packages/commit/55dd03c84c6ef7624ed3512b4d69b95c13b3af90)) * Eccvm sumcheck with commitments to round univariates ([#11206](https://github.com/AztecProtocol/aztec-packages/issues/11206)) ([fe34b05](https://github.com/AztecProtocol/aztec-packages/commit/fe34b0580a308665c655a897c72f06bd05dcd4c4)) -* Gaztec ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) +* Aztec Playground ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) * Lazy wasm pt. 2 ([#11410](https://github.com/AztecProtocol/aztec-packages/issues/11410)) ([01510f4](https://github.com/AztecProtocol/aztec-packages/commit/01510f45aa5d385a08584df674d9caf9522e6be2)) * Lazy wasm pt.1 ([#11371](https://github.com/AztecProtocol/aztec-packages/issues/11371)) ([864bc6f](https://github.com/AztecProtocol/aztec-packages/commit/864bc6f34431dee17e76c476716821996d2ff9e5)) * Lazy wasm pt3 ([#11435](https://github.com/AztecProtocol/aztec-packages/issues/11435)) ([7068d05](https://github.com/AztecProtocol/aztec-packages/commit/7068d055d91a6e81e6fbb670e17c77ee209a1a80)) diff --git a/aztec-up/bin/docker-compose.sandbox.yml b/aztec-up/bin/docker-compose.sandbox.yml index b40cff1755f..2db528a2222 100644 --- a/aztec-up/bin/docker-compose.sandbox.yml +++ b/aztec-up/bin/docker-compose.sandbox.yml @@ -20,7 +20,7 @@ services: ports: - "${PXE_PORT:-8080}:${PXE_PORT:-8080}" environment: - LOG_LEVEL: '${LOG_LEVEL:-info; verbose: simulator:avm:debug_log}' + LOG_LEVEL: '${LOG_LEVEL:-info; warn: sequencer; verbose: simulator:avm:debug_log}' HOST_WORKDIR: "${PWD}" # Loaded from the user shell to show log files absolute path in host ETHEREUM_HOST: ${ETHEREUM_HOST:-http://ethereum}:${ANVIL_PORT:-8545} L1_CHAIN_ID: 31337 diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 326579c7396..76edb13bd92 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 56503f9cc78e45654f431720318316ca2cc9789d - parent = 61614b1a0fa4a766b1ad5090a29f92a122511806 + commit = 5190efcf768c10fd5d5e1502c030f9641a79698f + parent = 52bbf1432500f7701deda8d75bf6ff454d37b024 method = merge cmdver = 0.4.6 diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index e04702f2ccd..806eca3c3c2 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## [0.74.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.73.0...barretenberg-v0.74.0) (2025-02-04) + + +### Features + +* UltraHonkZK contract ([#11553](https://github.com/AztecProtocol/aztec-packages/issues/11553)) ([a68369f](https://github.com/AztecProtocol/aztec-packages/commit/a68369fd1f12d00e037a2626b2bbc17375054883)) + + +### Bug Fixes + +* Barretenber/stdlib/logic bugs ([#11651](https://github.com/AztecProtocol/aztec-packages/issues/11651)) ([dddab22](https://github.com/AztecProtocol/aztec-packages/commit/dddab22934b3abb798dbf204bccb68b557ee2193)) +* Barretenberg/stdlib/logic bugs (redo) ([#11691](https://github.com/AztecProtocol/aztec-packages/issues/11691)) ([6d0bad7](https://github.com/AztecProtocol/aztec-packages/commit/6d0bad77b2ffdc966462cc333faa9cea4b21f4dc)) +* Revert "barretenberg/stdlib/logic bugs" ([#11689](https://github.com/AztecProtocol/aztec-packages/issues/11689)) ([b99570d](https://github.com/AztecProtocol/aztec-packages/commit/b99570d416f4c4c59f38e47a8677b476c5c06f0b)) + + +### Miscellaneous + +* Ensure new kv-store is used on the server ([#11662](https://github.com/AztecProtocol/aztec-packages/issues/11662)) ([aee1420](https://github.com/AztecProtocol/aztec-packages/commit/aee14208a42f9b5b7f9aef4b6e0d92e303a265c1)) +* Remove some templates in templates ([#11698](https://github.com/AztecProtocol/aztec-packages/issues/11698)) ([61614b1](https://github.com/AztecProtocol/aztec-packages/commit/61614b1a0fa4a766b1ad5090a29f92a122511806)) +* Turn on masking in ultra and mega zk + oink clean-up ([#11693](https://github.com/AztecProtocol/aztec-packages/issues/11693)) ([08e96fe](https://github.com/AztecProtocol/aztec-packages/commit/08e96fee292c53afa645a00a8d2689d01e8136d5)) + ## [0.73.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.72.1...barretenberg-v0.73.0) (2025-02-01) diff --git a/barretenberg/acir_tests/sol-test/src/index.js b/barretenberg/acir_tests/sol-test/src/index.js index 465b309042a..7800eeabe0b 100644 --- a/barretenberg/acir_tests/sol-test/src/index.js +++ b/barretenberg/acir_tests/sol-test/src/index.js @@ -9,6 +9,7 @@ const NUMBER_OF_FIELDS_IN_PLONK_PROOF = 93; const NUMBER_OF_FIELDS_IN_HONK_PROOF = 443; const NUMBER_OF_FIELDS_IN_HONK_ZK_PROOF = 494; +const WRONG_PROOF_LENGTH = "0xed74ac0a"; const WRONG_PUBLIC_INPUTS_LENGTH = "0xfa066593"; const SUMCHECK_FAILED = "0x9fc3a218"; const SHPLEMINI_FAILED = "0xa5d82e8a"; @@ -60,7 +61,6 @@ const testingHonk = getEnvVarCanBeUndefined("TESTING_HONK"); const hasZK = getEnvVarCanBeUndefined("HAS_ZK"); const verifierContract = hasZK ? "ZKVerifier.sol" : "Verifier.sol"; -console.log(verifierContract); export const compilationInput = { language: "Solidity", sources: { @@ -260,6 +260,10 @@ try { if (testingHonk) { var errorType = e.data; switch (errorType) { + case WRONG_PROOF_LENGTH: + throw new Error( + "Proof length wrong. Check the constant and the proof surgery." + ); case WRONG_PUBLIC_INPUTS_LENGTH: throw new Error("Number of inputs in the proof is wrong"); case SUMCHECK_FAILED: diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 066cdad2ebd..54cb373d38e 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.73.0 # x-release-please-version + VERSION 0.74.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 0091837f26e..00b99bcb269 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -26,6 +26,8 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 18) # We target clang18 and need this, eventually warning should be fixed or this will be unconditional. add_compile_options(-Wno-vla-cxx-extension) + # This gets in the way of a valid designated initializer pattern (i.e. MyClass my_class{ .my_member = init_value }) + add_compile_options(-Wno-missing-field-initializers) endif() endif() diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp new file mode 100644 index 00000000000..db2e6992bb3 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/claim_batcher.hpp @@ -0,0 +1,128 @@ +#pragma once +#include "barretenberg/common/ref_vector.hpp" +#include + +namespace bb { + +/** + * @brief Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini + * @details Stores references to the commitments/evaluations of unshifted and shifted polynomials to be batched + * opened via Shplemini. Aggregates the commitments and batching scalars for each batch into the corresponding + * containers for Shplemini. Computes the batched evaluation. Contains logic for computing the per-batch scalars + * used to batch each set of claims (see details below). + * @note This class performs the actual batching of the evaluations but not of the commitments. The latter are + * simply appended to a larger container, along with the scalars used to batch them. This is because Shplemini + * is optimized to perform a single batch mul that includes all commitments from each stage of the PCS. See + * description of ShpleminiVerifier for more details. + * + */ +template struct ClaimBatcher_ { + using Fr = typename Curve::ScalarField; + using Commitment = typename Curve::AffineElement; + + struct Batch { + RefVector commitments; + RefVector evaluations; + // scalar used for batching the claims, excluding the power of batching challenge \rho + Fr scalar = 0; + }; + + std::optional unshifted; // commitments and evaluations of unshifted polynomials + std::optional shifted; // commitments of to-be-shifted-by-1 polys, evals of their shifts + std::optional right_shifted_by_k; // commitments of to-be-right-shifted-by-k polys, evals of their shifts + + Batch get_unshifted() { return (unshifted) ? *unshifted : Batch{}; } + Batch get_shifted() { return (shifted) ? *shifted : Batch{}; } + Batch get_right_shifted_by_k() { return (right_shifted_by_k) ? *right_shifted_by_k : Batch{}; } + + size_t k_shift_magnitude = 0; // magnitude of right-shift-by-k (assumed even) + + Fr get_unshifted_batch_scalar() const { return unshifted ? unshifted->scalar : Fr{ 0 }; } + + /** + * @brief Compute scalars used to batch each set of claims, excluding contribution from batching challenge \rho + * @details Computes scalars s_0, s_1, s_2 given by + * \f[ + * - s_0 = \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right) \f], + * - s_1 = \frac{1}{r} \times \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) + * - s_2 = r^{k} \times \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right) + * \f] + * where the scalars used to batch the claims are given by + * \f[ + * \left( + * - s_0, + * \ldots, + * - \rho^{i+k-1} \times s_0, + * - \rho^{i+k} \times s_1, + * \ldots, + * - \rho^{k+m-1} \times s_1 + * \right) + * \f] + * + * @param inverse_vanishing_eval_pos 1/(z-r) + * @param inverse_vanishing_eval_neg 1/(z+r) + * @param nu_challenge ν (shplonk batching challenge) + * @param r_challenge r (gemini evaluation challenge) + */ + void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_pos, + const Fr& inverse_vanishing_eval_neg, + const Fr& nu_challenge, + const Fr& r_challenge) + { + if (unshifted) { + // (1/(z−r) + ν/(z+r)) + unshifted->scalar = inverse_vanishing_eval_pos + nu_challenge * inverse_vanishing_eval_neg; + } + if (shifted) { + // r⁻¹ ⋅ (1/(z−r) − ν/(z+r)) + shifted->scalar = + r_challenge.invert() * (inverse_vanishing_eval_pos - nu_challenge * inverse_vanishing_eval_neg); + } + if (right_shifted_by_k) { + // r^k ⋅ (1/(z−r) + ν/(z+r)) + right_shifted_by_k->scalar = r_challenge.pow(k_shift_magnitude) * + (inverse_vanishing_eval_pos + nu_challenge * inverse_vanishing_eval_neg); + } + } + + /** + * @brief Append the commitments and scalars from each batch of claims to the Shplemini batch mul input vectors; + * update the batched evaluation and the running batching challenge (power of rho) in place. + * + * @param commitments commitment inputs to the single Shplemini batch mul + * @param scalars scalar inputs to the single Shplemini batch mul + * @param batched_evaluation running batched evaluation of the committed multilinear polynomials + * @param rho multivariate batching challenge \rho + * @param rho_power current power of \rho used in the batching scalar + */ + void update_batch_mul_inputs_and_batched_evaluation(std::vector& commitments, + std::vector& scalars, + Fr& batched_evaluation, + const Fr& rho, + Fr& rho_power) + { + // Append the commitments/scalars from a given batch to the corresponding containers; update the batched + // evaluation and the running batching challenge in place + auto aggregate_claim_data_and_update_batched_evaluation = [&](const Batch& batch, Fr& rho_power) { + for (auto [commitment, evaluation] : zip_view(batch.commitments, batch.evaluations)) { + commitments.emplace_back(std::move(commitment)); + scalars.emplace_back(-batch.scalar * rho_power); + batched_evaluation += evaluation * rho_power; + rho_power *= rho; + } + }; + + // Incorporate the claim data from each batch of claims that is present + if (unshifted) { + aggregate_claim_data_and_update_batched_evaluation(*unshifted, rho_power); + } + if (shifted) { + aggregate_claim_data_and_update_batched_evaluation(*shifted, rho_power); + } + if (right_shifted_by_k) { + aggregate_claim_data_and_update_batched_evaluation(*right_shifted_by_k, rho_power); + } + } +}; + +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp index 7b4aaf0f035..ab4c5b9df1b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -1,6 +1,7 @@ #pragma once #include "barretenberg/commitment_schemes/claim.hpp" +#include "barretenberg/commitment_schemes/claim_batcher.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -104,11 +105,12 @@ template class GeminiProver_ { * @brief Class responsible for computation of the batched multilinear polynomials required by the Gemini protocol * @details Opening multivariate polynomials using Gemini requires the computation of three batched polynomials. The * first, here denoted A₀, is a linear combination of all polynomials to be opened. If we denote the linear - * combinations (based on challenge rho) of the unshifted and the to-be-shited-by-1 polynomials by F and G, - * respectively, then A₀ = F + G/X. This polynomial is "folded" in Gemini to produce d-1 univariate polynomials - * Fold_i, i = 1, ..., d-1. The second and third are the partially evaluated batched polynomials A₀₊ = F + G/r, and - * A₀₋ = F - G/r. These are required in order to prove the opening of shifted polynomials G_i/X from the commitments - * to their unshifted counterparts G_i. + * combinations (based on challenge rho) of the unshifted, to-be-shifted-by-1, and to-be-right-shifted-by-k + * polynomials by F, G, and H respectively, then A₀ = F + G/X + X^k*H. (Note: 'k' is assumed even and thus a factor + * (-1)^k in not needed for the evaluation at -r). This polynomial is "folded" in Gemini to produce d-1 univariate + * polynomials Fold_i, i = 1, ..., d-1. The second and third are the partially evaluated batched polynomials A₀₊ = F + * + G/r + r^K*H, and A₀₋ = F - G/r + r^K*H. These are required in order to prove the opening of shifted polynomials + * G_i/X, X^k*H_i and from the commitments to their unshifted counterparts G_i and H_i. * @note TODO(https://github.com/AztecProtocol/barretenberg/issues/1223): There are certain operations herein that * could be made more efficient by e.g. reusing already initialized polynomials, possibly at the expense of clarity. */ @@ -122,9 +124,13 @@ template class GeminiProver_ { RefVector unshifted; // set of unshifted polynomials RefVector to_be_shifted_by_one; // set of polynomials to be left shifted by 1 + RefVector to_be_shifted_by_k; // set of polynomials to be right shifted by k + + size_t k_shift_magnitude = 0; // magnitude of right-shift-by-k (assumed even) Polynomial batched_unshifted; // linear combination of unshifted polynomials Polynomial batched_to_be_shifted_by_one; // linear combination of to-be-shifted polynomials + Polynomial batched_to_be_shifted_by_k; // linear combination of to-be-shifted-by-k polynomials public: PolynomialBatcher(const size_t full_batched_size) @@ -135,10 +141,17 @@ template class GeminiProver_ { bool has_unshifted() const { return unshifted.size() > 0; } bool has_to_be_shifted_by_one() const { return to_be_shifted_by_one.size() > 0; } + bool has_to_be_shifted_by_k() const { return to_be_shifted_by_k.size() > 0; } // Set references to the polynomials to be batched void set_unshifted(RefVector polynomials) { unshifted = polynomials; } void set_to_be_shifted_by_one(RefVector polynomials) { to_be_shifted_by_one = polynomials; } + void set_to_be_shifted_by_k(RefVector polynomials, const size_t shift_magnitude) + { + ASSERT(k_shift_magnitude % 2 == 0); // k must be even for the formulas herein to be valid + to_be_shifted_by_k = polynomials; + k_shift_magnitude = shift_magnitude; + } // Initialize the random polynomial used to add randomness to the batched polynomials for ZK void set_random_polynomial(Polynomial&& random) @@ -169,19 +182,26 @@ template class GeminiProver_ { // if necessary, add randomness to the full batched polynomial for ZK if (has_random_polynomial) { - full_batched += random_polynomial; + full_batched += random_polynomial; // A₀ += rand } // compute the linear combination F of the unshifted polynomials if (has_unshifted()) { batch(batched_unshifted, unshifted); - full_batched += batched_unshifted; // A₀ = F + full_batched += batched_unshifted; // A₀ += F } // compute the linear combination G of the to-be-shifted polynomials if (has_to_be_shifted_by_one()) { batch(batched_to_be_shifted_by_one, to_be_shifted_by_one); - full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ = F + G/X + full_batched += batched_to_be_shifted_by_one.shifted(); // A₀ += G/X + } + + // compute the linear combination H of the to-be-shifted-by-k polynomials + if (has_to_be_shifted_by_k()) { + batched_to_be_shifted_by_k = Polynomial(full_batched_size - k_shift_magnitude, full_batched_size, 0); + batch(batched_to_be_shifted_by_k, to_be_shifted_by_k); + full_batched += batched_to_be_shifted_by_k.right_shifted(k_shift_magnitude); // A₀ += X^k * H } return full_batched; @@ -206,14 +226,20 @@ template class GeminiProver_ { A_0_pos += batched_unshifted; // A₀₊ += F } + if (has_to_be_shifted_by_k()) { + Fr r_pow_k = r_challenge.pow(k_shift_magnitude); // r^k + batched_to_be_shifted_by_k *= r_pow_k; + A_0_pos += batched_to_be_shifted_by_k; // A₀₊ += r^k * H + } + Polynomial A_0_neg = A_0_pos; if (has_to_be_shifted_by_one()) { Fr r_inv = r_challenge.invert(); // r⁻¹ batched_to_be_shifted_by_one *= r_inv; // G = G/r - A_0_pos += batched_to_be_shifted_by_one; // A₀₊ = F + G/r - A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ = F - G/r + A_0_pos += batched_to_be_shifted_by_one; // A₀₊ += G/r + A_0_neg -= batched_to_be_shifted_by_one; // A₀₋ -= G/r } return { A_0_pos, A_0_neg }; @@ -252,6 +278,7 @@ template class GeminiVerifier_ { using Fr = typename Curve::ScalarField; using GroupElement = typename Curve::Element; using Commitment = typename Curve::AffineElement; + using ClaimBatcher = ClaimBatcher_; public: /** @@ -268,10 +295,7 @@ template class GeminiVerifier_ { */ static std::vector> reduce_verification( std::span multilinear_challenge, - RefSpan unshifted_evaluations, - RefSpan shifted_evaluations, - RefSpan unshifted_commitments, - RefSpan to_be_shifted_commitments, + ClaimBatcher& claim_batcher, auto& transcript, const std::vector>& concatenation_group_commitments = {}, RefSpan concatenated_evaluations = {}) @@ -288,13 +312,15 @@ template class GeminiVerifier_ { Fr batched_evaluation = Fr(0); Fr batching_scalar = Fr(1); - for (auto [eval, comm] : zip_view(unshifted_evaluations, unshifted_commitments)) { + for (auto [eval, comm] : + zip_view(claim_batcher.get_unshifted().evaluations, claim_batcher.get_unshifted().commitments)) { batched_evaluation += eval * batching_scalar; batched_commitment_unshifted += comm * batching_scalar; batching_scalar *= rho; } - for (auto [eval, comm] : zip_view(shifted_evaluations, to_be_shifted_commitments)) { + for (auto [eval, comm] : + zip_view(claim_batcher.get_shifted().evaluations, claim_batcher.get_shifted().commitments)) { batched_evaluation += eval * batching_scalar; batched_commitment_to_be_shifted += comm * batching_scalar; batching_scalar *= rho; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp index 8d93f1ec5b6..060db23f561 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -8,7 +8,6 @@ using namespace bb; template class GeminiTest : public CommitmentTest { using GeminiProver = GeminiProver_; - using PolynomialBatcher = GeminiProver::PolynomialBatcher; using GeminiVerifier = GeminiVerifier_; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; @@ -30,7 +29,7 @@ template class GeminiTest : public CommitmentTest { } void execute_gemini_and_verify_claims(std::vector& multilinear_evaluation_point, - MockWitnessGenerator instance_witness) + MockClaimGenerator mock_claims) { auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -38,7 +37,7 @@ template class GeminiTest : public CommitmentTest { // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_output = GeminiProver::prove( - this->n, instance_witness.polynomial_batcher, multilinear_evaluation_point, ck, prover_transcript); + this->n, mock_claims.polynomial_batcher, multilinear_evaluation_point, ck, prover_transcript); // Check that the Fold polynomials have been evaluated correctly in the prover this->verify_batch_opening_pair(prover_output); @@ -49,13 +48,8 @@ template class GeminiTest : public CommitmentTest { // - Single opening pair: {r, \hat{a}_0} // - 2 partially evaluated Fold polynomial commitments [Fold_{r}^(0)] and [Fold_{-r}^(0)] // Aggregate: d+1 opening pairs and d+1 Fold poly commitments into verifier claim - auto verifier_claims = - GeminiVerifier::reduce_verification(multilinear_evaluation_point, - RefVector(instance_witness.unshifted_evals), - RefVector(instance_witness.shifted_evals), - RefVector(instance_witness.unshifted_commitments), - RefVector(instance_witness.to_be_shifted_commitments), - verifier_transcript); + auto verifier_claims = GeminiVerifier::reduce_verification( + multilinear_evaluation_point, mock_claims.claim_batcher, verifier_transcript); // Check equality of the opening pairs computed by prover and verifier for (auto [prover_claim, verifier_claim] : zip_view(prover_output, verifier_claims)) { @@ -66,7 +60,7 @@ template class GeminiTest : public CommitmentTest { void execute_gemini_and_verify_claims_with_concatenation( std::vector& multilinear_evaluation_point, - MockWitnessGenerator instance_witness, + MockClaimGenerator mock_claims, RefSpan> concatenated_polynomials = {}, RefSpan concatenated_evaluations = {}, const std::vector>>& groups_to_be_concatenated = {}, @@ -79,7 +73,7 @@ template class GeminiTest : public CommitmentTest { // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_output = GeminiProver::prove(this->n, - instance_witness.polynomial_batcher, + mock_claims.polynomial_batcher, multilinear_evaluation_point, ck, prover_transcript, @@ -95,15 +89,11 @@ template class GeminiTest : public CommitmentTest { // - Single opening pair: {r, \hat{a}_0} // - 2 partially evaluated Fold polynomial commitments [Fold_{r}^(0)] and [Fold_{-r}^(0)] // Aggregate: d+1 opening pairs and d+1 Fold poly commitments into verifier claim - auto verifier_claims = - GeminiVerifier::reduce_verification(multilinear_evaluation_point, - RefVector(instance_witness.unshifted_evals), - RefVector(instance_witness.shifted_evals), - RefVector(instance_witness.unshifted_commitments), - RefVector(instance_witness.to_be_shifted_commitments), - verifier_transcript, - concatenation_group_commitments, - concatenated_evaluations); + auto verifier_claims = GeminiVerifier::reduce_verification(multilinear_evaluation_point, + mock_claims.claim_batcher, + verifier_transcript, + concatenation_group_commitments, + concatenated_evaluations); // Check equality of the opening pairs computed by prover and verifier for (auto [prover_claim, verifier_claim] : zip_view(prover_output, verifier_claims)) { @@ -119,18 +109,20 @@ TYPED_TEST_SUITE(GeminiTest, ParamsTypes); TYPED_TEST(GeminiTest, Single) { auto u = this->random_evaluation_point(this->log_n); - auto instance_witness = MockWitnessGenerator(this->n, 1, 0, u, this->ck); + MockClaimGenerator mock_claims( + this->n, /*num_polynomials*/ 1, /*num_to_be_shifted*/ 0, /*num_to_be_right_shifted_by_k*/ 0, u, this->ck); - this->execute_gemini_and_verify_claims(u, instance_witness); + this->execute_gemini_and_verify_claims(u, mock_claims); } TYPED_TEST(GeminiTest, SingleShift) { auto u = this->random_evaluation_point(this->log_n); - auto instance_witness = MockWitnessGenerator(this->n, 0, 1, u, this->ck); + MockClaimGenerator mock_claims( + this->n, /*num_polynomials*/ 1, /*num_to_be_shifted*/ 1, /*num_to_be_right_shifted_by_k*/ 0, u, this->ck); - this->execute_gemini_and_verify_claims(u, instance_witness); + this->execute_gemini_and_verify_claims(u, mock_claims); } TYPED_TEST(GeminiTest, Double) @@ -138,9 +130,10 @@ TYPED_TEST(GeminiTest, Double) auto u = this->random_evaluation_point(this->log_n); - auto instance_witness = MockWitnessGenerator(this->n, 2, 0, u, this->ck); + MockClaimGenerator mock_claims( + this->n, /*num_polynomials*/ 2, /*num_to_be_shifted*/ 0, /*num_to_be_right_shifted_by_k*/ 0, u, this->ck); - this->execute_gemini_and_verify_claims(u, instance_witness); + this->execute_gemini_and_verify_claims(u, mock_claims); } TYPED_TEST(GeminiTest, DoubleWithShift) @@ -148,23 +141,25 @@ TYPED_TEST(GeminiTest, DoubleWithShift) auto u = this->random_evaluation_point(this->log_n); - auto instance_witness = MockWitnessGenerator(this->n, 2, 1, u, this->ck); + MockClaimGenerator mock_claims( + this->n, /*num_polynomials*/ 2, /*num_to_be_shifted*/ 1, /*num_to_be_right_shifted_by_k*/ 0, u, this->ck); - this->execute_gemini_and_verify_claims(u, instance_witness); + this->execute_gemini_and_verify_claims(u, mock_claims); } TYPED_TEST(GeminiTest, DoubleWithShiftAndConcatenation) { auto u = this->random_evaluation_point(this->log_n); - auto instance_witness = MockWitnessGenerator(this->n, 2, 0, u, this->ck); + MockClaimGenerator mock_claims( + this->n, /*num_polynomials*/ 2, /*num_to_be_shifted*/ 0, /*num_to_be_right_shifted_by_k*/ 0, u, this->ck); auto [concatenation_groups, concatenated_polynomials, c_evaluations, concatenation_groups_commitments] = generate_concatenation_inputs(u, /*num_concatenated=*/3, /*concatenation_index=*/2, this->ck); this->execute_gemini_and_verify_claims_with_concatenation( u, - instance_witness, + mock_claims, RefVector(concatenated_polynomials), RefVector(c_evaluations), to_vector_of_ref_vectors(concatenation_groups), diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp index 1f874317870..3da495da900 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -24,8 +24,8 @@ class IPATest : public CommitmentTest { using GeminiProver = GeminiProver_; using GeminiVerifier = GeminiVerifier_; using ShpleminiVerifier = ShpleminiVerifier_; - using ClaimBatcher = ShpleminiVerifier::ClaimBatcher; - using ClaimBatch = ShpleminiVerifier::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; static std::shared_ptr ck; static std::shared_ptr vk; @@ -248,7 +248,12 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) // point. auto mle_opening_point = this->random_evaluation_point(small_log_n); // sometimes denoted 'u' - auto instance_witness = MockWitnessGenerator(small_n, 2, 0, mle_opening_point, ck); + MockClaimGenerator mock_claims(small_n, + /*num_polynomials*/ 2, + /*num_to_be_shifted*/ 0, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -257,7 +262,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = - GeminiProver::prove(small_n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(small_n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript); PCS::compute_opening_proof(ck, opening_claim, prover_transcript); @@ -265,12 +270,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); auto gemini_verifier_claim = - GeminiVerifier::reduce_verification(mle_opening_point, - RefVector(instance_witness.unshifted_evals), - RefVector(instance_witness.shifted_evals), - RefVector(instance_witness.unshifted_commitments), - RefVector(instance_witness.to_be_shifted_commitments), - verifier_transcript); + GeminiVerifier::reduce_verification(mle_opening_point, mock_claims.claim_batcher, verifier_transcript); const auto shplonk_verifier_claim = ShplonkVerifier::reduce_verification(vk->get_g1_identity(), gemini_verifier_claim, verifier_transcript); @@ -283,7 +283,12 @@ TEST_F(IPATest, ShpleminiIPAWithShift) // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random // point. auto mle_opening_point = this->random_evaluation_point(small_log_n); // sometimes denoted 'u' - auto instance_witness = MockWitnessGenerator(small_n, 2, 0, mle_opening_point, ck); + MockClaimGenerator mock_claims(small_n, + /*num_polynomials*/ 2, + /*num_to_be_shifted*/ 0, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); // Run the full prover PCS protocol: @@ -292,14 +297,14 @@ TEST_F(IPATest, ShpleminiIPAWithShift) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = - GeminiProver::prove(small_n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(small_n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript); PCS::compute_opening_proof(ck, opening_claim, prover_transcript); auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim( - small_n, instance_witness.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript); + small_n, mock_claims.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript); auto result = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, vk, verifier_transcript); // auto result = PCS::reduce_verify(vk, shplonk_verifier_claim, verifier_transcript); @@ -315,7 +320,12 @@ TEST_F(IPATest, ShpleminiIPAShiftsRemoval) // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random // point. auto mle_opening_point = this->random_evaluation_point(small_log_n); // sometimes denoted 'u' - auto instance_witness = MockWitnessGenerator(small_n, 4, 2, mle_opening_point, ck); + MockClaimGenerator mock_claims(small_n, + /*num_polynomials*/ 4, + /*num_to_be_shifted*/ 2, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -325,7 +335,7 @@ TEST_F(IPATest, ShpleminiIPAShiftsRemoval) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = - GeminiProver::prove(small_n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(small_n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); const auto opening_claim = ShplonkProver::prove(ck, prover_opening_claims, prover_transcript); PCS::compute_opening_proof(ck, opening_claim, prover_transcript); @@ -346,7 +356,7 @@ TEST_F(IPATest, ShpleminiIPAShiftsRemoval) auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(small_n, - instance_witness.claim_batcher, + mock_claims.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript, diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp index 0284c50ed1e..5bac7124bcd 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -105,7 +105,12 @@ TEST_F(KZGTest, GeminiShplonkKzgWithShift) // point. std::vector mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u' - auto instance_witness = MockWitnessGenerator(n, 2, 1, mle_opening_point, ck); + MockClaimGenerator mock_claims(n, + /*num_polynomials*/ 2, + /*num_to_be_shifted*/ 1, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -115,7 +120,7 @@ TEST_F(KZGTest, GeminiShplonkKzgWithShift) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = - GeminiProver::prove(n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) @@ -133,12 +138,7 @@ TEST_F(KZGTest, GeminiShplonkKzgWithShift) // Gemini verifier output: // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1 auto gemini_verifier_claim = - GeminiVerifier::reduce_verification(mle_opening_point, - RefVector(instance_witness.unshifted_evals), - RefVector(instance_witness.shifted_evals), - RefVector(instance_witness.unshifted_commitments), - RefVector(instance_witness.to_be_shifted_commitments), - verifier_transcript); + GeminiVerifier::reduce_verification(mle_opening_point, mock_claims.claim_batcher, verifier_transcript); // Shplonk verifier claim: commitment [Q] - [Q_z], opening point (z_challenge, 0) const auto shplonk_verifier_claim = @@ -159,7 +159,12 @@ TEST_F(KZGTest, ShpleminiKzgWithShift) // point. std::vector mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u' - auto instance_witness = MockWitnessGenerator(n, 4, 2, mle_opening_point, ck); + MockClaimGenerator mock_claims(n, + /*num_polynomials*/ 4, + /*num_to_be_shifted*/ 2, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -169,7 +174,7 @@ TEST_F(KZGTest, ShpleminiKzgWithShift) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 auto prover_opening_claims = - GeminiProver::prove(n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) @@ -187,7 +192,7 @@ TEST_F(KZGTest, ShpleminiKzgWithShift) // Gemini verifier output: // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1 const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim( - n, instance_witness.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript); + n, mock_claims.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript); const auto pairing_points = PCS::reduce_verify_batch_opening_claim(batch_opening_claim, verifier_transcript); // Final pairing check: e([Q] - [Q_z] + z[W], [1]_2) = e([W], [x]_2) @@ -200,7 +205,12 @@ TEST_F(KZGTest, ShpleminiKzgWithShiftAndConcatenation) std::vector mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u' // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random // point. - auto instance_witness = MockWitnessGenerator(n, 4, 2, mle_opening_point, ck); + MockClaimGenerator mock_claims(n, + /*num_polynomials*/ 4, + /*num_to_be_shifted*/ 2, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto [concatenation_groups, concatenated_polynomials, c_evaluations, concatenation_groups_commitments] = generate_concatenation_inputs(mle_opening_point, /*num_concatenated=*/3, /*concatenation_index=*/2, ck); @@ -213,7 +223,7 @@ TEST_F(KZGTest, ShpleminiKzgWithShiftAndConcatenation) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 const auto prover_opening_claims = GeminiProver::prove(n, - instance_witness.polynomial_batcher, + mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript, @@ -237,7 +247,7 @@ TEST_F(KZGTest, ShpleminiKzgWithShiftAndConcatenation) // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1 const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(n, - instance_witness.claim_batcher, + mock_claims.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript, @@ -260,7 +270,12 @@ TEST_F(KZGTest, ShpleminiKzgShiftsRemoval) std::vector mle_opening_point = random_evaluation_point(log_n); // sometimes denoted 'u' // Generate multilinear polynomials, their commitments (genuine and mocked) and evaluations (genuine) at a random // point. - auto instance_witness = MockWitnessGenerator(n, 4, 2, mle_opening_point, ck); + MockClaimGenerator mock_claims(n, + /*num_polynomials*/ 4, + /*num_to_be_shifted*/ 2, + /*num_to_be_right_shifted_by_k*/ 0, + mle_opening_point, + ck); auto prover_transcript = NativeTranscript::prover_init_empty(); @@ -270,7 +285,7 @@ TEST_F(KZGTest, ShpleminiKzgShiftsRemoval) // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 // - (d+1) Fold polynomials Fold_{r}^(0), Fold_{-r}^(0), and Fold^(i), i = 0, ..., d-1 const auto prover_opening_claims = - GeminiProver::prove(n, instance_witness.polynomial_batcher, mle_opening_point, ck, prover_transcript); + GeminiProver::prove(n, mock_claims.polynomial_batcher, mle_opening_point, ck, prover_transcript); // Shplonk prover output: // - opening pair: (z_challenge, 0) @@ -301,7 +316,7 @@ TEST_F(KZGTest, ShpleminiKzgShiftsRemoval) // Gemini verifier output: // - claim: d+1 commitments to Fold_{r}^(0), Fold_{-r}^(0), Fold^(l), d+1 evaluations a_0_pos, a_l, l = 0:d-1 const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(n, - instance_witness.claim_batcher, + mock_claims.claim_batcher, mle_opening_point, vk->get_g1_identity(), verifier_transcript, diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp index 5611885640a..040c32cce97 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/commitment_schemes/claim.hpp" +#include "barretenberg/commitment_schemes/claim_batcher.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/commitment_schemes/gemini/gemini_impl.hpp" #include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" @@ -194,110 +195,9 @@ template class ShpleminiVerifier_ { using VK = VerifierCommitmentKey; using ShplonkVerifier = ShplonkVerifier_; using GeminiVerifier = GeminiVerifier_; + using ClaimBatcher = ClaimBatcher_; public: - struct ClaimBatch { - RefVector commitments; - RefVector evaluations; - // scalar used for batching the claims, excluding the power of batching challenge \rho - Fr scalar = 0; - }; - - /** - * @brief Logic to support batching opening claims for unshifted and shifted polynomials in Shplemini - * @details Stores references to the commitments/evaluations of unshifted and shifted polynomials to be batched - * opened via Shplemini. Aggregates the commitments and batching scalars for each batch into the corresponding - * containers for Shplemini. Computes the batched evaluation. Contains logic for computing the per-batch scalars - * used to batch each set of claims (see details below). - * @note This class performs the actual batching of the evaluations but not of the commitments. The latter are - * simply appended to a larger container, along with the scalars used to batch them. This is because Shplemini - * is optimized to perform a single batch mul that includes all commitments from each stage of the PCS. See - * description of ShpleminiVerifier for more details. - * - */ - struct ClaimBatcher { - std::optional unshifted; // commitments and evaluations of unshifted polynomials - std::optional shifted; // commitments of to-be-shifted-by-1 polys, evals of their shifts - - Fr get_unshifted_batch_scalar() const { return unshifted ? unshifted->scalar : Fr{ 0 }; } - - /** - * @brief Compute scalars used to batch each set of claims, excluding contribution from batching challenge \rho - * @details Computes scalars s_0 and s_1 given by - * \f[ - * - s_0 = \left(\frac{1}{z-r} + \nu \times \frac{1}{z+r}\right) \f], - * - s_1 = \left(\frac{1}{z-r} - \nu \times \frac{1}{z+r}\right) - * \f] - * where the scalars used to batch the claims are given by - * \f[ - * \left( - * - s_0, - * \ldots, - * - \rho^{i+k-1} \times s_0, - * - \rho^{i+k} \times \frac{1}{r} \times s_1, - * \ldots, - * - \rho^{k+m-1} \times \frac{1}{r} \times s_1 - * \right) - * \f] - * - * @param inverse_vanishing_eval_pos 1/(z-r) - * @param inverse_vanishing_eval_neg 1/(z+r) - * @param nu_challenge ν (shplonk batching challenge) - * @param r_challenge r (gemini evaluation challenge) - */ - void compute_scalars_for_each_batch(const Fr& inverse_vanishing_eval_pos, - const Fr& inverse_vanishing_eval_neg, - const Fr& nu_challenge, - const Fr& r_challenge) - { - if (unshifted) { - // (1/(z−r) + ν/(z+r)) - unshifted->scalar = inverse_vanishing_eval_pos + nu_challenge * inverse_vanishing_eval_neg; - } - if (shifted) { - // r⁻¹ ⋅ (1/(z−r) − ν/(z+r)) - shifted->scalar = - r_challenge.invert() * (inverse_vanishing_eval_pos - nu_challenge * inverse_vanishing_eval_neg); - } - } - - /** - * @brief Append the commitments and scalars from each batch of claims to the Shplemini batch mul input vectors; - * update the batched evaluation and the running batching challenge (power of rho) in place. - * - * @param commitments commitment inputs to the single Shplemini batch mul - * @param scalars scalar inputs to the single Shplemini batch mul - * @param batched_evaluation running batched evaluation of the committed multilinear polynomials - * @param rho multivariate batching challenge \rho - * @param rho_power current power of \rho used in the batching scalar - */ - void update_batch_mul_inputs_and_batched_evaluation(std::vector& commitments, - std::vector& scalars, - Fr& batched_evaluation, - const Fr& rho, - Fr& rho_power) - { - // Append the commitments/scalars from a given batch to the corresponding containers; update the batched - // evaluation and the running batching challenge in place - auto aggregate_claim_data_and_update_batched_evaluation = [&](const ClaimBatch& batch, Fr& rho_power) { - for (auto [commitment, evaluation] : zip_view(batch.commitments, batch.evaluations)) { - commitments.emplace_back(std::move(commitment)); - scalars.emplace_back(-batch.scalar * rho_power); - batched_evaluation += evaluation * rho_power; - rho_power *= rho; - } - }; - - // Incorporate the claim data from each batch of claims that is present - if (unshifted) { - aggregate_claim_data_and_update_batched_evaluation(*unshifted, rho_power); - } - if (shifted) { - aggregate_claim_data_and_update_batched_evaluation(*shifted, rho_power); - } - } - }; - template static BatchOpeningClaim compute_batch_opening_claim( const Fr N, @@ -391,8 +291,8 @@ template class ShpleminiVerifier_ { // Compute the additional factors to be multiplied with unshifted and shifted commitments when lazily // reconstructing the commitment of Q_z - claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], - inverse_vanishing_evals[1], + claim_batcher.compute_scalars_for_each_batch(inverse_vanishing_evals[0], // 1/(z − r) + inverse_vanishing_evals[1], // 1/(z + r) shplonk_batching_challenge, gemini_evaluation_challenge); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp index aa79bf451c7..eeb5b0fbb59 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplemini.test.cpp @@ -23,9 +23,11 @@ template class ShpleminiTest : public CommitmentTestrandom_evaluation_point(this->log_n); - auto pcs_instance_witness = - MockWitnessGenerator(this->n, this->num_polynomials, this->num_shiftable, mle_opening_point, ck); + MockClaimGenerator mock_claims(this->n, + /*num_polynomials*/ this->num_polynomials, + /*num_to_be_shifted*/ this->num_shiftable, + /*num_to_be_right_shifted_by_k*/ this->num_right_shiftable_by_k, + mle_opening_point, + ck); // Collect multilinear evaluations std::vector rhos = gemini::powers_of_rho(rho, this->num_polynomials + this->num_shiftable); - // Compute batched multivariate evaluation - Fr batched_evaluation = Fr(0); - size_t idx = 0; - for (auto& eval : pcs_instance_witness.unshifted_evals) { - batched_evaluation += eval * rhos[idx]; - idx++; - } - - for (auto& eval : pcs_instance_witness.shifted_evals) { - batched_evaluation += eval * rhos[idx]; - idx++; - } + // Lambda to compute batched multivariate evaluation + auto update_batched_eval = [&](Fr& batched_eval, const std::vector& evaluations, Fr& rho_power) { + for (auto& eval : evaluations) { + batched_eval += eval * rho_power; + rho_power *= rho; + } + }; + + Fr rho_power(1); + Fr batched_evaluation(0); + update_batched_eval(batched_evaluation, mock_claims.unshifted.evals, rho_power); + update_batched_eval(batched_evaluation, mock_claims.to_be_shifted.evals, rho_power); + update_batched_eval(batched_evaluation, mock_claims.to_be_right_shifted_by_k.evals, rho_power); + + // Lambda to compute batched commitment + auto compute_batched_commitment = [&](const std::vector& commitments, Fr& rho_power) { + GroupElement batched = GroupElement::zero(); + for (auto& comm : commitments) { + batched += comm * rho_power; + rho_power *= rho; + } + return batched; + }; // Compute batched commitments manually - idx = 0; - GroupElement batched_commitment_unshifted = GroupElement::zero(); - for (auto& comm : pcs_instance_witness.unshifted_commitments) { - batched_commitment_unshifted += comm * rhos[idx]; - idx++; - } - - GroupElement batched_commitment_to_be_shifted = GroupElement::zero(); - for (auto& comm : pcs_instance_witness.to_be_shifted_commitments) { - batched_commitment_to_be_shifted += comm * rhos[idx]; - idx++; - } + rho_power = Fr(1); + GroupElement batched_commitment_unshifted = + compute_batched_commitment(mock_claims.unshifted.commitments, rho_power); + GroupElement batched_commitment_to_be_shifted = + compute_batched_commitment(mock_claims.to_be_shifted.commitments, rho_power); + GroupElement batched_commitment_to_be_right_shifted_by_k = + compute_batched_commitment(mock_claims.to_be_right_shifted_by_k.commitments, rho_power); // Compute expected result manually - GroupElement commitment_to_univariate = - batched_commitment_unshifted + batched_commitment_to_be_shifted * gemini_eval_challenge.invert(); + GroupElement to_be_right_shifted_by_k_contribution = + batched_commitment_to_be_right_shifted_by_k * + gemini_eval_challenge.pow(mock_claims.claim_batcher.k_shift_magnitude); + GroupElement to_be_shifted_contribution = batched_commitment_to_be_shifted * gemini_eval_challenge.invert(); + + GroupElement commitment_to_univariate_pos = + batched_commitment_unshifted + to_be_right_shifted_by_k_contribution + to_be_shifted_contribution; + GroupElement commitment_to_univariate_neg = - batched_commitment_unshifted - batched_commitment_to_be_shifted * gemini_eval_challenge.invert(); + batched_commitment_unshifted + to_be_right_shifted_by_k_contribution - to_be_shifted_contribution; GroupElement expected_result = - commitment_to_univariate * (shplonk_eval_challenge - gemini_eval_challenge).invert() + + commitment_to_univariate_pos * (shplonk_eval_challenge - gemini_eval_challenge).invert() + commitment_to_univariate_neg * (shplonk_batching_challenge * (shplonk_eval_challenge + gemini_eval_challenge).invert()); @@ -145,18 +163,18 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfMultivariateClaimBatching) Fr inverted_vanishing_eval_pos = (shplonk_eval_challenge - gemini_eval_challenge).invert(); Fr inverted_vanishing_eval_neg = (shplonk_eval_challenge + gemini_eval_challenge).invert(); - pcs_instance_witness.claim_batcher.compute_scalars_for_each_batch( + mock_claims.claim_batcher.compute_scalars_for_each_batch( inverted_vanishing_eval_pos, inverted_vanishing_eval_neg, shplonk_batching_challenge, gemini_eval_challenge); ShpleminiVerifier::batch_multivariate_opening_claims( - pcs_instance_witness.claim_batcher, rho, commitments, scalars, verifier_batched_evaluation); + mock_claims.claim_batcher, rho, commitments, scalars, verifier_batched_evaluation); // Final pairing check GroupElement shplemini_result = batch_mul_native(commitments, scalars); EXPECT_EQ(commitments.size(), - pcs_instance_witness.unshifted_commitments.size() + - pcs_instance_witness.to_be_shifted_commitments.size()); + mock_claims.unshifted.commitments.size() + mock_claims.to_be_shifted.commitments.size() + + mock_claims.to_be_right_shifted_by_k.commitments.size()); EXPECT_EQ(batched_evaluation, verifier_batched_evaluation); EXPECT_EQ(-expected_result, shplemini_result); } @@ -164,7 +182,6 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) { using Curve = TypeParam::Curve; using GeminiProver = GeminiProver_; - using PolynomialBatcher = GeminiProver::PolynomialBatcher; using ShpleminiVerifier = ShpleminiVerifier_; using ShplonkVerifier = ShplonkVerifier_; using Fr = typename Curve::ScalarField; @@ -183,18 +200,18 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) std::vector mle_opening_point = this->random_evaluation_point(this->log_n); - auto pcs_instance_witness = - MockWitnessGenerator(this->n, this->num_polynomials, this->num_shiftable, mle_opening_point, ck); + MockClaimGenerator mock_claims(this->n, + /*num_polynomials*/ this->num_polynomials, + /*num_to_be_shifted*/ this->num_shiftable, + /*num_to_be_right_shifted_by_k*/ this->num_right_shiftable_by_k, + mle_opening_point, + ck); // Collect multilinear evaluations std::vector rhos = gemini::powers_of_rho(rho, this->num_polynomials + this->num_shiftable); - PolynomialBatcher polynomial_batcher(this->n); - polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); - polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); - Fr running_scalar = Fr(1); - Polynomial batched = polynomial_batcher.compute_batched(rho, running_scalar); + Polynomial batched = mock_claims.polynomial_batcher.compute_batched(rho, running_scalar); // Compute: // - (d+1) opening pairs: {r, \hat{a}_0}, {-r^{2^i}, a_i}, i = 0, ..., d-1 @@ -208,7 +225,7 @@ TYPED_TEST(ShpleminiTest, CorrectnessOfGeminiClaimBatching) } auto [A_0_pos, A_0_neg] = GeminiProver::compute_partially_evaluated_batch_polynomials( - this->log_n, polynomial_batcher, gemini_eval_challenge); + this->log_n, mock_claims.polynomial_batcher, gemini_eval_challenge); const auto opening_claims = GeminiProver::construct_univariate_opening_claims( this->log_n, std::move(A_0_pos), std::move(A_0_neg), std::move(fold_polynomials), gemini_eval_challenge); @@ -272,7 +289,6 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using CK = typename TypeParam::CommitmentKey; - using PolynomialBatcher = GeminiProver_::PolynomialBatcher; // Initialize transcript and commitment key auto prover_transcript = TypeParam::Transcript::prover_init_empty(); @@ -291,8 +307,12 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) const_size_mle_opening_point.begin() + this->log_n); // Generate random prover polynomials, compute their evaluations and commitments - MockWitnessGenerator pcs_instance_witness( - this->n, this->num_polynomials, this->num_shiftable, mle_opening_point, ck); + MockClaimGenerator mock_claims(this->n, + /*num_polynomials*/ this->num_polynomials, + /*num_to_be_shifted*/ this->num_shiftable, + /*num_to_be_right_shifted_by_k*/ this->num_right_shiftable_by_k, + mle_opening_point, + ck); // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges const Fr claimed_inner_product = SmallSubgroupIPAProver::compute_claimed_inner_product( @@ -304,13 +324,9 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, const_size_mle_opening_point, claimed_inner_product, prover_transcript, ck); - PolynomialBatcher polynomial_batcher(this->n); - polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); - polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); - // Reduce to KZG or IPA based on the curve used in the test Flavor const auto opening_claim = ShpleminiProver::prove(this->n, - polynomial_batcher, + mock_claims.polynomial_batcher, const_size_mle_opening_point, ck, prover_transcript, @@ -350,7 +366,7 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKNoSumcheckOpenings) // Run Shplemini const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(this->n, - pcs_instance_witness.claim_batcher, + mock_claims.claim_batcher, const_size_mle_opening_point, this->vk()->get_g1_identity(), verifier_transcript, @@ -387,7 +403,6 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) using ShpleminiProver = ShpleminiProver_; using ShpleminiVerifier = ShpleminiVerifier_; - using PolynomialBatcher = GeminiProver_::PolynomialBatcher; std::shared_ptr ck = create_commitment_key(4096); @@ -400,10 +415,10 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) // Generate masking polynomials for Sumcheck Round Univariates ZKSumcheckData zk_sumcheck_data(this->log_n, prover_transcript, ck); // Generate mock witness - MockWitnessGenerator pcs_instance_witness(this->n, 1); + MockClaimGenerator mock_claims(this->n, 1); // Generate valid sumcheck polynomials of given length - pcs_instance_witness.template compute_sumcheck_opening_data( + mock_claims.template compute_sumcheck_opening_data( this->n, this->log_n, this->sumcheck_univariate_length, challenge, ck); // Compute the sum of the Libra constant term and Libra univariates evaluated at Sumcheck challenges @@ -416,19 +431,15 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) SmallSubgroupIPAProver small_subgroup_ipa_prover( zk_sumcheck_data, challenge, claimed_inner_product, prover_transcript, ck); - PolynomialBatcher polynomial_batcher(this->n); - polynomial_batcher.set_unshifted(RefVector(pcs_instance_witness.unshifted_polynomials)); - polynomial_batcher.set_to_be_shifted_by_one(RefVector(pcs_instance_witness.to_be_shifted_polynomials)); - // Reduce proving to a single claimed fed to KZG or IPA const auto opening_claim = ShpleminiProver::prove(this->n, - polynomial_batcher, + mock_claims.polynomial_batcher, challenge, ck, prover_transcript, small_subgroup_ipa_prover.get_witness_polynomials(), - pcs_instance_witness.round_univariates, - pcs_instance_witness.sumcheck_evaluations); + mock_claims.round_univariates, + mock_claims.sumcheck_evaluations); if constexpr (std::is_same_v) { IPA::compute_opening_proof(this->ck(), opening_claim, prover_transcript); @@ -460,19 +471,18 @@ TYPED_TEST(ShpleminiTest, ShpleminiZKWithSumcheckOpenings) bool consistency_checked = true; // Run Shplemini - const auto batch_opening_claim = - ShpleminiVerifier::compute_batch_opening_claim(this->n, - pcs_instance_witness.claim_batcher, - challenge, - this->vk()->get_g1_identity(), - verifier_transcript, - {}, - true, - &consistency_checked, - libra_commitments, - libra_evaluation, - pcs_instance_witness.sumcheck_commitments, - pcs_instance_witness.sumcheck_evaluations); + const auto batch_opening_claim = ShpleminiVerifier::compute_batch_opening_claim(this->n, + mock_claims.claim_batcher, + challenge, + this->vk()->get_g1_identity(), + verifier_transcript, + {}, + true, + &consistency_checked, + libra_commitments, + libra_evaluation, + mock_claims.sumcheck_commitments, + mock_claims.sumcheck_evaluations); // Verify claim using KZG or IPA if constexpr (std::is_same_v) { auto result = diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/mock_witness_generator.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/mock_witness_generator.hpp index d0740f21bdd..d9603643861 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/mock_witness_generator.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/utils/mock_witness_generator.hpp @@ -13,24 +13,30 @@ namespace bb { * * @tparam Curve */ -template struct MockWitnessGenerator { +template struct MockClaimGenerator { public: using CommitmentKey = bb::CommitmentKey; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using Polynomial = bb::Polynomial; using PolynomialBatcher = bb::GeminiProver_::PolynomialBatcher; - using ClaimBatcher = bb::ShpleminiVerifier_::ClaimBatcher; - using ClaimBatch = bb::ShpleminiVerifier_::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; std::shared_ptr ck; - std::vector unshifted_polynomials = {}; - std::vector to_be_shifted_polynomials; + + struct ClaimData { + std::vector polys; + std::vector commitments; + std::vector evals; + }; + + ClaimData unshifted; + ClaimData to_be_shifted; + ClaimData to_be_right_shifted_by_k; + std::vector const_size_mle_opening_point; - std::vector unshifted_commitments = {}; - std::vector to_be_shifted_commitments; - std::vector unshifted_evals = {}; - std::vector shifted_evals; + PolynomialBatcher polynomial_batcher; ClaimBatcher claim_batcher; @@ -39,71 +45,87 @@ template struct MockWitnessGenerator { std::vector sumcheck_commitments; std::vector> sumcheck_evaluations; - MockWitnessGenerator(const size_t n, - const size_t num_polynomials, - const size_t num_shiftable, - const std::vector& mle_opening_point, - std::shared_ptr& commitment_key) + static constexpr size_t k_magnitude = 6; // mock shift magnitude for right-shift-by-k (assumed even) + + /** + * @brief Construct claim data for a set of random polynomials with the specified type + * @note All to-be-shifted polynomials have an unshifted counterpart so the total number of claims is + * num_polynomials + num_to_be_shifted + * + * @param poly_size size of mock polynomials + * @param num_polynomials total number of unique polynomials + * @param num_to_be_shifted number of polynomials to-be-shifted + * @param mle_opening_point + * @param commitment_key + */ + MockClaimGenerator(const size_t poly_size, + const size_t num_polynomials, + const size_t num_to_be_shifted, + const size_t num_to_be_right_shifted_by_k, + const std::vector& mle_opening_point, + std::shared_ptr& commitment_key) : ck(commitment_key) // Initialize the commitment key - , unshifted_polynomials(num_polynomials) - , to_be_shifted_polynomials(num_shiftable) - , polynomial_batcher(n) - - { - construct_instance_and_witnesses(n, mle_opening_point); - } + , polynomial_batcher(poly_size) - void construct_instance_and_witnesses(size_t n, const std::vector& mle_opening_point) { - - const size_t num_unshifted = unshifted_polynomials.size() - to_be_shifted_polynomials.size(); - - // Constructs polynomials that are not shifted - if (!unshifted_polynomials.empty()) { - for (size_t idx = 0; idx < num_unshifted; idx++) { - unshifted_polynomials[idx] = Polynomial::random(n); - unshifted_commitments.push_back(ck->commit(unshifted_polynomials[idx])); - unshifted_evals.push_back(unshifted_polynomials[idx].evaluate_mle(mle_opening_point)); - } + const size_t total_num_to_be_shifted = num_to_be_shifted + num_to_be_right_shifted_by_k; + ASSERT(num_polynomials >= total_num_to_be_shifted); + const size_t num_not_to_be_shifted = num_polynomials - total_num_to_be_shifted; + + // Construct claim data for polynomials that are NOT to be shifted + for (size_t idx = 0; idx < num_not_to_be_shifted; idx++) { + Polynomial poly = Polynomial::random(poly_size); + unshifted.commitments.push_back(ck->commit(poly)); + unshifted.evals.push_back(poly.evaluate_mle(mle_opening_point)); + unshifted.polys.push_back(std::move(poly)); } - // Constructs polynomials that are being shifted - for (auto& poly : to_be_shifted_polynomials) { - poly = Polynomial::random(n, /*shiftable*/ 1); - const Commitment comm = this->ck->commit(poly); - to_be_shifted_commitments.push_back(comm); - shifted_evals.push_back(poly.evaluate_mle(mle_opening_point, true)); + // Construct claim data for polynomials that are to-be-shifted + for (size_t idx = 0; idx < num_to_be_shifted; idx++) { + Polynomial poly = Polynomial::random(poly_size, /*shiftable*/ 1); + Commitment commitment = ck->commit(poly); + to_be_shifted.commitments.push_back(commitment); + to_be_shifted.evals.push_back(poly.shifted().evaluate_mle(mle_opening_point)); + to_be_shifted.polys.push_back(poly.share()); + // Populate the unshifted counterpart in the unshifted claims + unshifted.commitments.push_back(commitment); + unshifted.evals.push_back(poly.evaluate_mle(mle_opening_point)); + unshifted.polys.push_back(std::move(poly)); } - size_t idx = num_unshifted; - - // Add unshifted evaluations of shiftable polynomials - if (!unshifted_polynomials.empty()) { - for (const auto& [poly, comm] : zip_view(to_be_shifted_polynomials, to_be_shifted_commitments)) { - unshifted_polynomials[idx] = poly; - unshifted_commitments.push_back(comm); - unshifted_evals.push_back(poly.evaluate_mle(mle_opening_point)); - idx++; - } + // Construct claim data for polynomials that are to-be-right-shifted-by-k + for (size_t idx = 0; idx < num_to_be_right_shifted_by_k; idx++) { + Polynomial poly = Polynomial::random(poly_size - k_magnitude, poly_size, 0); + Commitment commitment = ck->commit(poly); + to_be_right_shifted_by_k.commitments.push_back(commitment); + to_be_right_shifted_by_k.evals.push_back(poly.right_shifted(k_magnitude).evaluate_mle(mle_opening_point)); + to_be_right_shifted_by_k.polys.push_back(poly.share()); + // Populate the unshifted counterpart in the unshifted claims + unshifted.commitments.push_back(commitment); + unshifted.evals.push_back(poly.evaluate_mle(mle_opening_point)); + unshifted.polys.push_back(std::move(poly)); } - polynomial_batcher.set_unshifted(RefVector(unshifted_polynomials)); - polynomial_batcher.set_to_be_shifted_by_one(RefVector(to_be_shifted_polynomials)); + polynomial_batcher.set_unshifted(RefVector(unshifted.polys)); + polynomial_batcher.set_to_be_shifted_by_one(RefVector(to_be_shifted.polys)); + polynomial_batcher.set_to_be_shifted_by_k(RefVector(to_be_right_shifted_by_k.polys), k_magnitude); claim_batcher = - ClaimBatcher{ .unshifted = ClaimBatch{ RefVector(unshifted_commitments), RefVector(unshifted_evals) }, - .shifted = ClaimBatch{ RefVector(to_be_shifted_commitments), RefVector(shifted_evals) } }; + ClaimBatcher{ .unshifted = ClaimBatch{ RefVector(unshifted.commitments), RefVector(unshifted.evals) }, + .shifted = ClaimBatch{ RefVector(to_be_shifted.commitments), RefVector(to_be_shifted.evals) }, + .right_shifted_by_k = ClaimBatch{ RefVector(to_be_right_shifted_by_k.commitments), + RefVector(to_be_right_shifted_by_k.evals) }, + .k_shift_magnitude = k_magnitude }; } // Generate zero polynomials to test edge cases in PCS - MockWitnessGenerator(const size_t n, const size_t num_zero_polynomials) - : unshifted_polynomials(num_zero_polynomials) - , polynomial_batcher(n) + MockClaimGenerator(const size_t n, const size_t num_zero_polynomials) + : polynomial_batcher(n) { for (size_t idx = 0; idx < num_zero_polynomials; idx++) { - unshifted_polynomials[idx] = Polynomial(n); - unshifted_commitments.push_back(Commitment::infinity()); - unshifted_evals.push_back(Fr(0)); + unshifted.polys.emplace_back(n); + unshifted.commitments.push_back(Commitment::infinity()); + unshifted.evals.push_back(Fr(0)); } } diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp index b38c38f94bd..221e5cebc4d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes_recursion/shplemini.test.cpp @@ -5,6 +5,7 @@ #include "barretenberg/commitment_schemes/ipa/ipa.hpp" #include "barretenberg/commitment_schemes/kzg/kzg.hpp" #include "barretenberg/commitment_schemes/shplonk/shplonk.hpp" +#include "barretenberg/commitment_schemes/utils/mock_witness_generator.hpp" #include "barretenberg/srs/global_crs.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/curves/grumpkin.hpp" @@ -30,7 +31,6 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) using Curve = typename stdlib::bn254; using NativeCurve = typename Curve::NativeCurve; using Commitment = typename Curve::AffineElement; - using NativeCommitment = typename Curve::AffineElementNative; using NativeCurve = typename Curve::NativeCurve; using NativePCS = std::conditional_t, KZG, IPA>; using CommitmentKey = typename NativePCS::CK; @@ -38,61 +38,32 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) using ShpleminiVerifier = ShpleminiVerifier_; using Fr = typename Curve::ScalarField; using NativeFr = typename Curve::NativeCurve::ScalarField; - using Polynomial = bb::Polynomial; using Transcript = bb::BaseTranscript>; - using PolynomialBatcher = GeminiProver_::PolynomialBatcher; - using ClaimBatcher = ShpleminiVerifier::ClaimBatcher; - using ClaimBatch = ShpleminiVerifier::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; + using MockClaimGen = MockClaimGenerator; srs::init_crs_factory(bb::srs::get_ignition_crs_path()); auto run_shplemini = [](size_t log_circuit_size) { size_t N = 1 << log_circuit_size; - constexpr size_t NUM_UNSHIFTED = 2; - constexpr size_t NUM_SHIFTED = 1; + constexpr size_t NUM_POLYS = 5; + constexpr size_t NUM_SHIFTED = 2; + constexpr size_t NUM_RIGHT_SHIFTED_BY_K = 1; + + auto commitment_key = std::make_shared(16384); + std::vector u_challenge(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; ++idx) { u_challenge[idx] = NativeFr::random_element(&shplemini_engine); }; - // Construct some random multilinear polynomials f_i and their evaluations v_i = f_i(u) - std::vector f_polynomials; // unshifted polynomials - std::vector v_evaluations; - for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - f_polynomials.emplace_back(Polynomial::random(N, /*shiftable*/ 1)); - v_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge)); - } - - // Construct some "shifted" multilinear polynomials h_i as the left-shift-by-1 of f_i - std::vector g_polynomials; // to-be-shifted polynomials - std::vector h_polynomials; // shifts of the to-be-shifted polynomials - std::vector w_evaluations; - if constexpr (NUM_SHIFTED > 0) { - for (size_t i = 0; i < NUM_SHIFTED; ++i) { - g_polynomials.emplace_back(f_polynomials[i]); - h_polynomials.emplace_back(g_polynomials[i].shifted()); - w_evaluations.emplace_back(f_polynomials[i].evaluate_mle(u_challenge, true)); - } - } - // Compute commitments [f_i] - std::vector f_commitments; - auto commitment_key = std::make_shared(16384); - for (size_t i = 0; i < NUM_UNSHIFTED; ++i) { - f_commitments.emplace_back(commitment_key->commit(f_polynomials[i])); - } - // Construct container of commitments of the "to-be-shifted" polynomials [g_i] (= [f_i]) - std::vector g_commitments; - for (size_t i = 0; i < NUM_SHIFTED; ++i) { - g_commitments.emplace_back(f_commitments[i]); - } - - PolynomialBatcher polynomial_batcher(N); - polynomial_batcher.set_unshifted(RefVector(f_polynomials)); - polynomial_batcher.set_to_be_shifted_by_one(RefVector(g_polynomials)); + // Construct mock multivariate polynomial opening claims + MockClaimGen mock_claims(N, NUM_POLYS, NUM_SHIFTED, NUM_RIGHT_SHIFTED_BY_K, u_challenge, commitment_key); // Initialize an empty NativeTranscript auto prover_transcript = NativeTranscript::prover_init_empty(); auto prover_opening_claims = - ShpleminiProver::prove(N, polynomial_batcher, u_challenge, commitment_key, prover_transcript); + ShpleminiProver::prove(N, mock_claims.polynomial_batcher, u_challenge, commitment_key, prover_transcript); KZG::compute_opening_proof(commitment_key, prover_opening_claims, prover_transcript); Builder builder; StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(&builder, prover_transcript->proof_data); @@ -118,10 +89,16 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) }); return elements_in_circuit; }; - auto stdlib_f_commitments = commitments_to_witnesses(f_commitments); - auto stdlib_g_commitments = commitments_to_witnesses(g_commitments); - auto stdlib_v_evaluations = elements_to_witness(v_evaluations); - auto stdlib_w_evaluations = elements_to_witness(w_evaluations); + auto stdlib_unshifted_commitments = + commitments_to_witnesses(mock_claims.claim_batcher.get_unshifted().commitments); + auto stdlib_to_be_shifted_commitments = + commitments_to_witnesses(mock_claims.claim_batcher.get_shifted().commitments); + auto stdlib_to_be_right_shifted_commitments = + commitments_to_witnesses(mock_claims.claim_batcher.get_right_shifted_by_k().commitments); + auto stdlib_unshifted_evaluations = elements_to_witness(mock_claims.claim_batcher.get_unshifted().evaluations); + auto stdlib_shifted_evaluations = elements_to_witness(mock_claims.claim_batcher.get_shifted().evaluations); + auto stdlib_right_shifted_evaluations = + elements_to_witness(mock_claims.claim_batcher.get_right_shifted_by_k().evaluations); std::vector u_challenge_in_circuit; u_challenge_in_circuit.reserve(CONST_PROOF_SIZE_LOG_N); @@ -138,8 +115,11 @@ TEST(ShpleminiRecursionTest, ProveAndVerifySingle) }); ClaimBatcher claim_batcher{ - .unshifted = ClaimBatch{ RefVector(stdlib_f_commitments), RefVector(stdlib_v_evaluations) }, - .shifted = ClaimBatch{ RefVector(stdlib_g_commitments), RefVector(stdlib_w_evaluations) } + .unshifted = ClaimBatch{ RefVector(stdlib_unshifted_commitments), RefVector(stdlib_unshifted_evaluations) }, + .shifted = ClaimBatch{ RefVector(stdlib_to_be_shifted_commitments), RefVector(stdlib_shifted_evaluations) }, + .right_shifted_by_k = ClaimBatch{ RefVector(stdlib_to_be_right_shifted_commitments), + RefVector(stdlib_right_shifted_evaluations) }, + .k_shift_magnitude = MockClaimGen::k_magnitude }; const auto opening_claim = ShpleminiVerifier::compute_batch_opening_claim(Fr::from_witness(&builder, N), diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp index 5cc27bc8868..c18cf1f311a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_contract.hpp @@ -1430,13 +1430,22 @@ abstract contract BaseHonkVerifier is IVerifier { numPublicInputs = _numPublicInputs; } + error ProofLengthWrong(); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); + // Number of field elements in a ultra honk zero knowledge proof + uint256 constant PROOF_SIZE = 443; + function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) { + // Check the received proof is the expected size where each field element is 32 bytes + if (proof.length != PROOF_SIZE * 32) { + revert ProofLengthWrong(); + } + Honk.VerificationKey memory vk = loadVerificationKey(); Honk.Proof memory p = TranscriptLib.loadProof(proof); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp index 92a4cd944e0..4e5eef6c2c6 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/honk_zk_contract.hpp @@ -1489,13 +1489,21 @@ interface IVerifier { // Errors + error ProofLengthWrong(); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); error GeminiChallengeInSubgroup(); error ConsistencyCheckFailed(); + uint256 constant PROOF_SIZE = 494; + function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool verified) { + // Check the received proof is the expected size where each field element is 32 bytes + if (proof.length != PROOF_SIZE * 32) { + revert ProofLengthWrong(); + } + Honk.VerificationKey memory vk = loadVerificationKey(); Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp index ee44fac3dcd..66855d0982d 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_flavor.hpp @@ -60,8 +60,6 @@ class ECCVMFlavor { static constexpr size_t NUM_SHIFTED_ENTITIES = 26; // The number of entities in DerivedWitnessEntities that are not going to be shifted. static constexpr size_t NUM_DERIVED_WITNESS_ENTITIES_NON_SHIFTED = 1; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_ENTITIES; // A container to be fed to ShpleminiVerifier to avoid redundant scalar muls, the first number is the index of the // first witness to be shifted. static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS = diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index a1cbe3aaec0..8a7d43f880b 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -14,8 +14,8 @@ bool ECCVMVerifier::verify_proof(const ECCVMProof& proof) using Shplemini = ShpleminiVerifier_; using Shplonk = ShplonkVerifier_; using OpeningClaim = OpeningClaim; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; RelationParameters relation_parameters; transcript = std::make_shared(proof.pre_ipa_proof); diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 7a1cddb0069..bb779cfc6c4 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -242,15 +242,11 @@ auto get_unshifted_then_shifted(const auto& all_entities) * @details The "partial length" of a relation is 1 + the degree of the relation, where any challenges used in the * relation are as constants, not as variables.. */ -template constexpr size_t compute_max_partial_relation_length() +template constexpr size_t compute_max_partial_relation_length() { constexpr auto seq = std::make_index_sequence>(); return [](std::index_sequence) { - if constexpr (ZK) { - return std::max({ std::tuple_element_t::ZK_RELATION_LENGTH... }); - } else { - return std::max({ std::tuple_element_t::RELATION_LENGTH... }); - } + return std::max({ std::tuple_element_t::RELATION_LENGTH... }); }(seq); } @@ -259,15 +255,11 @@ template constexpr size_t compute_max_partial_ * @details The "total length" of a relation is 1 + the degree of the relation, where any challenges used in the * relation are regarded as variables. */ -template constexpr size_t compute_max_total_relation_length() +template constexpr size_t compute_max_total_relation_length() { constexpr auto seq = std::make_index_sequence>(); return [](std::index_sequence) { - if constexpr (ZK) { - return std::max({ std::tuple_element_t::ZK_TOTAL_RELATION_LENGTH... }); - } else { - return std::max({ std::tuple_element_t::TOTAL_RELATION_LENGTH... }); - } + return std::max({ std::tuple_element_t::TOTAL_RELATION_LENGTH... }); }(seq); } diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp index d85fd78eb5f..7730c839586 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.cpp @@ -345,6 +345,17 @@ template Polynomial Polynomial::shifted() const return result; } +template Polynomial Polynomial::right_shifted(const size_t magnitude) const +{ + // ensure that at least the last magnitude-many coefficients are virtual 0's + ASSERT((coefficients_.end_ + magnitude) <= virtual_size()); + Polynomial result; + result.coefficients_ = coefficients_; + result.coefficients_.start_ += magnitude; + result.coefficients_.end_ += magnitude; + return result; +} + template class Polynomial; template class Polynomial; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp index fdb196d06f8..077bc78f85e 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial.hpp @@ -162,6 +162,12 @@ template class Polynomial { */ Polynomial shifted() const; + /** + * @brief Returns a Polynomial equal to the right-shift-by-magnitude of self. + * @note Resulting Polynomial shares the memory of that used to generate it + */ + Polynomial right_shifted(const size_t magnitude) const; + /** * @brief evaluate multi-linear extension p(X_0,…,X_{n-1}) = \sum_i a_i*L_i(X_0,…,X_{n-1}) at u = * (u_0,…,u_{n-1}) If the polynomial is embedded into a lower dimension k; + const size_t SIZE = 10; + const size_t VIRTUAL_SIZE = 20; + const size_t START_IDX = 2; + const size_t SHIFT_MAGNITUDE = 5; + auto poly = Polynomial::random(SIZE, VIRTUAL_SIZE, START_IDX); + + // Instantiate the shift via the right_shifted method + auto poly_shifted = poly.right_shifted(SHIFT_MAGNITUDE); + + EXPECT_EQ(poly_shifted.size(), poly.size()); + EXPECT_EQ(poly_shifted.virtual_size(), poly.virtual_size()); + + // The shift is indeed the shift + for (size_t i = 0; i < SIZE; ++i) { + EXPECT_EQ(poly_shifted.get(i + SHIFT_MAGNITUDE), poly.get(i)); + } + + // If I change the original polynomial, the shift is updated accordingly + poly.at(3) = 25; + for (size_t i = 0; i < SIZE; ++i) { + EXPECT_EQ(poly_shifted.get(i + SHIFT_MAGNITUDE), poly.get(i)); + } +} + // Simple test/demonstration of share functionality TEST(Polynomial, Share) { diff --git a/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp index 653e86ce143..10801c0a275 100644 --- a/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/auxiliary_relation.hpp @@ -39,21 +39,6 @@ template class AuxiliaryRelationImpl { 6, // RAM consistency sub-relation 2 6 // RAM consistency sub-relation 3 }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // auxiliary sub-relation; - 2, // ROM consistency sub-relation 1: adjacent values match if adjacent indices match and next access is a read - // operation - 2, // ROM consistency sub-relation 2: index is monotonously increasing - 3, // RAM consistency sub-relation 1: adjacent values match if adjacent indices match and next access is a read - // operation - 2, // RAM consistency sub-relation 2: index is monotonously increasing - 2 // RAM consistency sub-relation 3: next gate access type is boolean - }; static constexpr std::array TOTAL_LENGTH_ADJUSTMENTS{ 1, // auxiliary sub-relation diff --git a/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp index efc977a3bd1..969ac3d833e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/databus_lookup_relation.hpp @@ -62,23 +62,6 @@ template class DatabusLookupRelationImpl { LOOKUP_SUBREL_LENGTH // log-derivative lookup argument subrelation (bus_idx 2) }; - static constexpr size_t INVERSE_SUBREL_WITNESS_DEGREE = 4; // witness degree of inverse correctness subrelation - static constexpr size_t LOOKUP_SUBREL_WITNESS_DEGREE = 4; // witness degree of log-deriv lookup subrelation - - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness - * polynomials, i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree - * does not exceed the subrelation partial degree, which is given by LENGTH - 1 in this case. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 0) - LOOKUP_SUBREL_WITNESS_DEGREE, // log-derivative lookup argument subrelation (bus_idx 0) - INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 1) - LOOKUP_SUBREL_WITNESS_DEGREE, // log-derivative lookup argument subrelation (bus_idx 1) - INVERSE_SUBREL_WITNESS_DEGREE, // inverse polynomial correctness subrelation (bus_idx 2) - LOOKUP_SUBREL_WITNESS_DEGREE // log-derivative lookup argument subrelation (bus_idx 2) - }; - static constexpr bool INVERSE_SUBREL_LIN_INDEPENDENT = true; // to be satisfied independently at each row static constexpr bool LOOKUP_SUBREL_LIN_INDEPENDENT = false; // to be satisfied as a sum across all rows diff --git a/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp index f8153988724..c34b933cb61 100644 --- a/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/delta_range_constraint_relation.hpp @@ -13,17 +13,6 @@ template class DeltaRangeConstraintRelationImpl { 6, // range constrain sub-relation 3 6 // range constrain sub-relation 4 }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 3, // range constrain sub-relation 1 - 3, // range constrain sub-relation 2 - 3, // range constrain sub-relation 3 - 3 // range constrain sub-relation 4 - }; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp index 355efe8476e..535f7ca6722 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_op_queue_relation.hpp @@ -17,21 +17,6 @@ template class EccOpQueueRelationImpl { 3, // op-queue-wire vanishes sub-relation 3 3 // op-queue-wire vanishes sub-relation 4 }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 1, // wire - op-queue-wire consistency sub-relation 1 - 1, // wire - op-queue-wire consistency sub-relation 2 - 1, // wire - op-queue-wire consistency sub-relation 3 - 1, // wire - op-queue-wire consistency sub-relation 4 - 1, // op-queue-wire vanishes sub-relation 1 - 1, // op-queue-wire vanishes sub-relation 2 - 1, // op-queue-wire vanishes sub-relation 3 - 1 // op-queue-wire vanishes sub-relation 4 - }; template inline static bool skip([[maybe_unused]] const AllEntities& in) { diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_bools_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_bools_relation.hpp index 211aeb9a786..7d06fd12190 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_bools_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_bools_relation.hpp @@ -20,18 +20,6 @@ template class ECCVMBoolsRelationImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - }; - - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 5; template static void accumulate(ContainerOverSubrelations& accumulator, diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp index 04486374550..d0b3f9d2d8a 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_lookup_relation.hpp @@ -20,19 +20,6 @@ template class ECCVMLookupRelationImpl { LENGTH, // grand product construction sub-relation LENGTH // left-shiftable polynomial sub-relation }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - LENGTH - 1, // grand product construction sub-relation - LENGTH - 1 // left-shiftable polynomial sub-relation - }; - - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 17; static constexpr std::array SUBRELATION_LINEARLY_INDEPENDENT = { true, false }; diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_msm_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_msm_relation.hpp index 22926ca59ec..0e2bcad6f40 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_msm_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_msm_relation.hpp @@ -40,16 +40,6 @@ template class ECCVMMSMRelationImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 15; template static void accumulate(ContainerOverSubrelations& accumulator, diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_point_table_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_point_table_relation.hpp index 213a29a0f27..43c4c4a0928 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_point_table_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_point_table_relation.hpp @@ -19,16 +19,8 @@ namespace bb { template class ECCVMPointTableRelationImpl { public: using FF = FF_; - static constexpr size_t ZK_RELATION_LENGTH = 11; static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 6, 6, 6, 6, 6, 6 }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ 5, 5, 5, 5, 5, 5 }; template static void accumulate(ContainerOverSubrelations& accumulator, diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp index d0e0ab35a23..1a5aff69369 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_set_relation.hpp @@ -16,19 +16,6 @@ template class ECCVMSetRelationImpl { 22, // grand product construction sub-relation 3 // left-shiftable polynomial sub-relation }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 21, // grand product construction sub-relation - 1 // left-shiftable polynomial sub-relation - }; - - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 43; template static Accumulator convert_to_wnaf(const auto& s0, const auto& s1) { diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_transcript_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_transcript_relation.hpp index fcb9f73e48b..e46af5c69a3 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_transcript_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_transcript_relation.hpp @@ -33,18 +33,7 @@ template class ECCVMTranscriptRelationImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in -witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does -not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 15; + template static void accumulate(ContainerOverSubrelations& accumulator, const AllEntities& in, diff --git a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_wnaf_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_wnaf_relation.hpp index f6e6c07b5bf..b47ddf5cc49 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_wnaf_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ecc_vm/ecc_wnaf_relation.hpp @@ -38,18 +38,6 @@ template class ECCVMWnafRelationImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - }; - - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 9; template static void accumulate(ContainerOverSubrelations& accumulator, diff --git a/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp index aa2812ec139..3b7966ba860 100644 --- a/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/elliptic_relation.hpp @@ -13,15 +13,6 @@ template class EllipticRelationImpl { 6, // x-coordinate sub-relation 6, // y-coordinate sub-relation }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 3, // x-coordinate sub-relation - 3, // y-coordinate sub-relation (because of point doubling) - }; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero diff --git a/barretenberg/cpp/src/barretenberg/relations/logderiv_lookup_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/logderiv_lookup_relation.hpp index 40699095590..46fbf47bbcb 100644 --- a/barretenberg/cpp/src/barretenberg/relations/logderiv_lookup_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/logderiv_lookup_relation.hpp @@ -22,15 +22,6 @@ template class LogDerivLookupRelationImpl { LENGTH, // inverse construction sub-relation LENGTH // log derivative lookup argument sub-relation }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // inverse construction sub-relation - 3, // log derivative lookup argument sub-relation - }; // Note: the required correction for the second sub-relation is technically +1 but the two corrections must agree // due to the way the relation algebra is written so both are set to +2. diff --git a/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp index 58438a3c03d..06aba09959e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/permutation_relation.hpp @@ -35,16 +35,6 @@ template class UltraPermutationRelationImpl { 0 // left-shiftable polynomial sub-relation }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 5, // grand product construction sub-relation - 1 // left-shiftable polynomial sub-relation - }; - /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * diff --git a/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp index 9bd988d273f..fadd4a46b8e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/poseidon2_external_relation.hpp @@ -12,17 +12,6 @@ template class Poseidon2ExternalRelationImpl { 7, // external poseidon2 round sub-relation for third value 7, // external poseidon2 round sub-relation for fourth value }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 5, // external poseidon2 round sub-relation for first value - 5, // external poseidon2 round sub-relation for second value - 5, // external poseidon2 round sub-relation for third value - 5, // external poseidon2 round sub-relation for fourth value - }; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero diff --git a/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp index 8f9d2ec7baa..11c866752d7 100644 --- a/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/poseidon2_internal_relation.hpp @@ -14,17 +14,6 @@ template class Poseidon2InternalRelationImpl { 7, // internal poseidon2 round sub-relation for third value 7, // internal poseidon2 round sub-relation for fourth value }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 5, // external poseidon2 round sub-relation for first value - 5, // external poseidon2 round sub-relation for second value - 5, // external poseidon2 round sub-relation for third value - 5, // external poseidon2 round sub-relation for fourth value - }; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero diff --git a/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp b/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp index faf646505f7..d340223077d 100644 --- a/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/relation_types.hpp @@ -30,10 +30,6 @@ concept HasSubrelationLinearlyIndependentMember = requires(T) { template concept HasParameterLengthAdjustmentsMember = requires { T::TOTAL_LENGTH_ADJUSTMENTS; }; -// The concept needed to adjust the sumcheck univariate lengths in the case of ZK Flavors and to avoid adding redundant -// constants to the relations that are not used by ZK flavors -template -concept HasWitnessDegrees = requires { T::SUBRELATION_WITNESS_DEGREES; }; /** * @brief Check whether a given subrelation is linearly independent from the other subrelations. @@ -70,27 +66,6 @@ consteval std::array c return RelationImpl::SUBRELATION_PARTIAL_LENGTHS; } }; -/** - * @brief This metod adjusts the subrelation partial lengths to ZK Flavors. - * - * @tparam RelationImpl - * @return consteval - */ -template -consteval std::array compute_zk_partial_subrelation_lengths() -{ - if constexpr (HasWitnessDegrees) { - constexpr size_t NUM_SUBRELATIONS = RelationImpl::SUBRELATION_PARTIAL_LENGTHS.size(); - std::array result; - for (size_t idx = 0; idx < NUM_SUBRELATIONS; idx++) { - result[idx] = - RelationImpl::SUBRELATION_PARTIAL_LENGTHS[idx] + RelationImpl::SUBRELATION_WITNESS_DEGREES[idx]; - } - return result; - } else { - return RelationImpl::SUBRELATION_PARTIAL_LENGTHS; - } -}; /** * @brief Get the subrelation accumulators for the Protogalaxy combiner calculation. @@ -164,18 +139,12 @@ template class Relation : public RelationImpl { static constexpr std::array SUBRELATION_TOTAL_LENGTHS = compute_total_subrelation_lengths(); - // Compute the subrelation partial lengths adjusted to ZK - static constexpr std::array ZK_PARTIAL_LENGTHS = - compute_zk_partial_subrelation_lengths(); static constexpr size_t RELATION_LENGTH = *std::max_element(RelationImpl::SUBRELATION_PARTIAL_LENGTHS.begin(), RelationImpl::SUBRELATION_PARTIAL_LENGTHS.end()); static constexpr size_t TOTAL_RELATION_LENGTH = *std::max_element(SUBRELATION_TOTAL_LENGTHS.begin(), SUBRELATION_TOTAL_LENGTHS.end()); - // Determine the maximum subrelation length in the case if ZK Flavors - static constexpr size_t ZK_TOTAL_RELATION_LENGTH = - *std::max_element(ZK_PARTIAL_LENGTHS.begin(), ZK_PARTIAL_LENGTHS.end()); template using ProtogalaxyTupleOfUnivariatesOverSubrelationsNoOptimisticSkipping = @@ -188,9 +157,6 @@ template class Relation : public RelationImpl { NUM_KEYS - 1>; using SumcheckTupleOfUnivariatesOverSubrelations = TupleOfUnivariates; - // The container constructor for sumcheck univariates corresponding to each subrelation in ZK Flavor's relations - using ZKSumcheckTupleOfUnivariatesOverSubrelations = - TupleOfUnivariates()>; using SumcheckArrayOfValuesOverSubrelations = ArrayOfValues; diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_decomposition_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_decomposition_relation.hpp index d71ef18f80f..a5f4956edbc 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_decomposition_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_decomposition_relation.hpp @@ -61,65 +61,7 @@ template class TranslatorDecompositionRelationImpl { 3, // decomposition of z1 into 2 limbs subrelation 3 // decomposition of z2 into 2 limbs subrelation }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // decomposition of P.x limb 0 into microlimbs subrelation - 2, // decomposition of P.x limb 1 into microlimbs subrelation - 2, // decomposition of P.x limb 2 into microlimbs subrelation - 2, // decomposition of P.x limb 3 into microlimbs subrelation - 2, // decomposition of P.y limb 0 into microlimbs subrelation - 2, // decomposition of P.y limb 1 into microlimbs subrelation - 2, // decomposition of P.y limb 2 into microlimbs subrelation - 2, // decomposition of P.y limb 3 into microlimbs subrelation - 2, // decomposition of z1 limb 0 into microlimbs subrelation - 2, // decomposition of z2 limb 0 into microlimbs subrelation - 2, // decomposition of z1 limb 1 into microlimbs subrelation - 2, // decomposition of z2 limb 1 into microlimbs subrelation - 2, // decomposition of accumulator limb 0 into microlimbs subrelation - 2, // decomposition of accumulator limb 1 into microlimbs subrelation - 2, // decomposition of accumulator limb 2 into microlimbs subrelation - 2, // decomposition of accumulator limb 3 into microlimbs subrelation - 2, // decomposition of quotient limb 0 into microlimbs subrelation - 2, // decomposition of quotient limb 1 into microlimbs subrelation - 2, // decomposition of quotient limb 2 into microlimbs subrelation - 2, // decomposition of quotient limb 3 into microlimbs subrelation - 2, // decomposition of low relation wide limb into microlimbs subrelation - 2, // decomposition of high relation wide limb into microlimbs subrelation - 2, // stricter constraint on highest microlimb of P.x limb 0 subrelation - 2, // stricter constraint on highest microlimb of P.x limb 1 subrelation - 2, // stricter constraint on highest microlimb of P.x limb 2 subrelation - 2, // stricter constraint on highest microlimb of P.x limb 3 subrelation - 2, // stricter constraint on highest microlimb of P.y limb 0 subrelation - 2, // stricter constraint on highest microlimb of P.y limb 1 subrelation - 2, // stricter constraint on highest microlimb of P.y limb 2 subrelation - 2, // stricter constraint on highest microlimb of P.y limb 3 subrelation - 2, // stricter constraint on highest microlimb of z1 limb 0 subrelation - 2, // stricter constraint on highest microlimb of z2 limb 0 subrelation - 2, // stricter constraint on highest microlimb of z1 limb 1 subrelation - 2, // stricter constraint on highest microlimb of z2 limb 1 subrelation - 2, // stricter constraint on highest microlimb of accumulator limb 0 subrelation - 2, // stricter constraint on highest microlimb of accumulator limb 1 subrelation - 2, // stricter constraint on highest microlimb of accumulator limb 2 subrelation - 2, // stricter constraint on highest microlimb of accumulator limb 3 subrelation - 2, // stricter constraint on highest microlimb of quotient limb 0 subrelation - 2, // stricter constraint on highest microlimb of quotient limb 1 subrelation - 2, // stricter constraint on highest microlimb of quotient limb 2 subrelation - 2, // stricter constraint on highest microlimb of quotient limb 3 subrelation - 2, // decomposition of x_lo into 2 limbs subrelation - 2, // decomposition of x_hi into 2 limbs subrelation - 2, // decomposition of y_lo into 2 limbs subrelation - 2, // decomposition of y_hi into 2 limbs subrelation - 2, // decomposition of z1 into 2 limbs subrelation - 2 // decomposition of z2 into 2 limbs subrelation - }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 5; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp index 448e95ca085..1515598dc88 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_delta_range_constraint_relation.hpp @@ -23,28 +23,6 @@ template class TranslatorDeltaRangeConstraintRelationImpl { 3 // ordered_range_constraints_4 ends with defined maximum value subrelation }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 5, // ordered_range_constraints_0 step in {0,1,2,3} subrelation - 5, // ordered_range_constraints_1 step in {0,1,2,3} subrelation - 5, // ordered_range_constraints_2 step in {0,1,2,3} subrelation - 5, // ordered_range_constraints_3 step in {0,1,2,3} subrelation - 5, // ordered_range_constraints_4 step in {0,1,2,3} subrelation - 2, // ordered_range_constraints_0 ends with defined maximum value subrelation - 2, // ordered_range_constraints_1 ends with defined maximum value subrelation - 2, // ordered_range_constraints_2 ends with defined maximum value subrelation - 2, // ordered_range_constraints_3 ends with defined maximum value subrelation - 2 // ordered_range_constraints_4 ends with defined maximum value subrelation - - }; - - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 11; /** * @brief Expression for the generalized permutation sort relation diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_extra_relations.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_extra_relations.hpp index d114a4cabd8..7692d7133fd 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_extra_relations.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_extra_relations.hpp @@ -12,17 +12,7 @@ template class TranslatorOpcodeConstraintRelationImpl { static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 7 // opcode constraint relation }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 6 // opcode constraint relation - }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 13; + /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * @@ -49,7 +39,6 @@ polynomials, template class TranslatorAccumulatorTransferRelationImpl { public: using FF = FF_; - static constexpr size_t ZK_RELATION_LENGTH = 5; // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 3; // degree((SOME_LAGRANGE)(A-B)) = 2 @@ -68,27 +57,7 @@ template class TranslatorAccumulatorTransferRelationImpl { 3 // accumulator limb 3 is equal to given result at the end of accumulation subrelation }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // transfer accumulator limb 0 at even index subrelation - 2, // transfer accumulator limb 1 at even index subrelation - 2, // transfer accumulator limb 2 at even index subrelation - 2, // transfer accumulator limb 3 at even index subrelation - 2, // accumulator limb 0 is zero at the start of accumulation subrelation - 2, // accumulator limb 1 is zero at the start of accumulation subrelation - 2, // accumulator limb 2 is zero at the start of accumulation subrelation - 2, // accumulator limb 3 is zero at the start of accumulation subrelation - 2, // accumulator limb 0 is equal to given result at the end of accumulation subrelation - 2, // accumulator limb 1 is equal to given result at the end of accumulation subrelation - 2, // accumulator limb 2 is equal to given result at the end of accumulation subrelation - 2 // accumulator limb 3 is equal to given result at the end of accumulation subrelation - }; /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * @@ -129,7 +98,6 @@ template class TranslatorZeroConstraintsRelationImpl { // 1 + polynomial degree of this relation static constexpr size_t RELATION_LENGTH = 3; // degree((some lagrange)(A)) = 2 - static constexpr size_t ZK_RELATION_LENGTH = 5; static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ 3, // p_x_low_limbs_range_constraint_0 is zero outside of the minicircuit 3, // p_x_low_limbs_range_constraint_1 is zero outside of the minicircuit @@ -197,79 +165,7 @@ template class TranslatorZeroConstraintsRelationImpl { 3, // quotient_high_limbs_range_constraint_tail is zero outside of the minicircuit }; - /** - * @brief For ZK-Flavors: Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // p_x_low_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // p_x_low_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // p_x_low_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // p_x_low_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // p_x_low_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_4 is zero outside of the minicircuit - 2, // relation_wide_limbs_range_constraint_0 is zero outside of the minicircuit - 2, // relation_wide_limbs_range_constraint_1 is zero outside of the minicircuit - 2, // relation_wide_limbs_range_constraint_2 is zero outside of the minicircuit - 2, // relation_wide_limbs_range_constraint_3 is zero outside of the minicircuit - 2, // p_x_low_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // p_x_high_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // p_y_low_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // p_y_high_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // z_low_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // z_high_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // accumulator_low_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // accumulator_high_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // quotient_low_limbs_range_constraint_tail is zero outside of the minicircuit - 2, // quotient_high_limbs_range_constraint_tail is zero outside of the minicircuit - }; /** * @brief Might return true if the contribution from all subrelations for the provided inputs is identically zero * diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_non_native_field_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_non_native_field_relation.hpp index 468a5c3ae08..b94fa346e97 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_non_native_field_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_non_native_field_relation.hpp @@ -14,19 +14,7 @@ template class TranslatorNonNativeFieldRelationImpl { 3, // Higher wide limb subrelation (checks result is 0 in higher mod 2¹³⁶), 3 // Prime subrelation (checks result in native field) }; - /** - * @brief Upper bound on the degrees of subrelations considered as polynomials only in witness -polynomials, - * i.e. all selectors and public polynomials are treated as constants. The subrelation witness degree does not - * exceed the subrelation partial degree given by SUBRELATION_PARTIAL_LENGTH - 1. - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 2, // Lower wide limb subrelation (checks result is 0 mod 2¹³⁶) - 2, // Higher wide limb subrelation (checks result is 0 in higher mod 2¹³⁶), - 2 // Prime subrelation (checks result in native field) - }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 5; + /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * diff --git a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp index 5279ca98d12..b5b6f276ab5 100644 --- a/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/translator_vm/translator_permutation_relation.hpp @@ -13,17 +13,7 @@ template class TranslatorPermutationRelationImpl { 7, // grand product construction sub-relation 3 // left-shiftable polynomial sub-relation }; - /** - * @brief The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ - 6, // grand product construction sub-relation - 1 // left-shiftable polynomial sub-relation - }; - // Max among {SUBRELATION_PARTIAL_LENGTH + SUBRELATION_WITNESS_DEGREE} - static constexpr size_t ZK_RELATION_LENGTH = 13; + inline static auto& get_grand_product_polynomial(auto& in) { return in.z_perm; } inline static auto& get_shifted_grand_product_polynomial(auto& in) { return in.z_perm_shift; } diff --git a/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp b/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp index dfb74d3a512..efa18235246 100644 --- a/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/ultra_arithmetic_relation.hpp @@ -12,13 +12,6 @@ template class UltraArithmeticRelationImpl { 5 // secondary arithmetic sub-relation }; - /** - * @brief For ZK-Flavors: The degrees of subrelations considered as polynomials only in witness polynomials, - * i.e. all selectors and public polynomials are treated as constants. - * - */ - static constexpr std::array SUBRELATION_WITNESS_DEGREES{ 2, 2 }; - /** * @brief Returns true if the contribution from all subrelations for the provided inputs is identically zero * diff --git a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp index d7d8e00884b..101dc7067a7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/eccvm_verifier/eccvm_recursive_verifier.cpp @@ -25,8 +25,8 @@ ECCVMRecursiveVerifier_::verify_proof(const ECCVMProof& proof) using Shplemini = ShpleminiVerifier_; using Shplonk = ShplonkVerifier_; using OpeningClaim = OpeningClaim; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; RelationParameters relation_parameters; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp index 1905d90f959..ad6f36b99d8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/decider_recursive_verifier.cpp @@ -18,8 +18,8 @@ std::array DeciderRecursiveVerifier_:: using Shplemini = ::bb::ShpleminiVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using Transcript = typename Flavor::Transcript; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(builder, proof); transcript = std::make_shared(stdlib_proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp index a6967859ae1..f5bda8819bc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_verifier/ultra_recursive_verifier.cpp @@ -45,8 +45,8 @@ UltraRecursiveVerifier_::Output UltraRecursiveVerifier_::verify_ using Shplemini = ::bb::ShpleminiVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using Transcript = typename Flavor::Transcript; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; Output output; StdlibProof honk_proof; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp index 6b9caf746de..b0a13bb542e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/translator_vm_verifier/translator_recursive_verifier.cpp @@ -65,8 +65,8 @@ std::array TranslatorRecursiveVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; StdlibProof stdlib_proof = bb::convert_native_proof_to_stdlib(builder, proof); transcript->load_proof(stdlib_proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_flavor.hpp index 1bf82af322a..f3162aa4f4f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/mega_flavor.hpp @@ -78,8 +78,6 @@ class MegaFlavor { // length = 3 static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; static constexpr size_t NUM_RELATIONS = std::tuple_size_v; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_WITNESSES; // For instances of this flavour, used in folding, we need a unique sumcheck batching challenges for each // subrelation. This is because using powers of alpha would increase the degree of Protogalaxy polynomial $G$ (the diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp index 2ed5aa7003a..85d817eea2b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_flavor.hpp @@ -60,9 +60,6 @@ class UltraFlavor { static constexpr RepeatedCommitmentsData REPEATED_COMMITMENTS = RepeatedCommitmentsData( NUM_PRECOMPUTED_ENTITIES, NUM_PRECOMPUTED_ENTITIES + NUM_WITNESS_ENTITIES, NUM_SHIFTED_WITNESSES); - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_WITNESSES; - // define the tuple of Relations that comprise the Sumcheck relation // Note: made generic for use in MegaRecursive. template diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp index b461e64698c..22695ea3a0f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_keccak_zk_flavor.hpp @@ -4,18 +4,6 @@ namespace bb { -/*! -\brief Child class of UltraFlavor that runs with ZK Sumcheck. -\details -Most of the properties of UltraFlavor are -inherited without any changes, except for the MAX_PARTIAL_RELATION_LENGTH which is now computed as a maximum of -SUBRELATION_PARTIAL_LENGTHS incremented by the corresponding SUBRELATION_WITNESS_DEGREES over all relations included in -UltraFlavor, which also affects the size of ExtendedEdges univariate containers. -Moreover, the container SumcheckTupleOfTuplesOfUnivariates is resized to reflect that masked -witness polynomials are of degree at most \f$2\f$ in each variable, and hence, for any subrelation, the corresponding -univariate accumuluator size has to be increased by the subrelation's witness degree. See more in -\ref docs/src/sumcheck-outline.md "Sumcheck Outline". -*/ class UltraKeccakZKFlavor : public UltraKeccakFlavor { public: // This flavor runs with ZK Sumcheck diff --git a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp index 31e3c830578..c5b10e22e7b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib_circuit_builders/ultra_zk_flavor.hpp @@ -7,14 +7,11 @@ namespace bb { /*! \brief Child class of UltraFlavor that runs with ZK Sumcheck. \details -Most of the properties of UltraFlavor are -inherited without any changes, except for the MAX_PARTIAL_RELATION_LENGTH which is now computed as a maximum of -SUBRELATION_PARTIAL_LENGTHS incremented by the corresponding SUBRELATION_WITNESS_DEGREES over all relations included in -UltraFlavor, which also affects the size of ExtendedEdges univariate containers. -Moreover, the container SumcheckTupleOfTuplesOfUnivariates is resized to reflect that masked -witness polynomials are of degree at most \f$2\f$ in each variable, and hence, for any subrelation, the corresponding -univariate accumuluator size has to be increased by the subrelation's witness degree. See more in -\ref docs/src/sumcheck-outline.md "Sumcheck Outline". +Most of the properties of UltraFlavor are inherited without any changes. However, the BATCHED_RELATION_PARTIAL_LENGTH is +incremented by 1, as we are using the sumcheck with disabled rows, where the main Honk relation is multiplied by a sum +of multilinear Lagranges. Additionally, the transcript contains extra elements, such as commitments and evaluations of +Libra polynomials used in Sumcheck to make it ZK, as well as a commitment and an evaluation of a hiding polynomials that +turns the PCS stage ZK. */ class UltraZKFlavor : public UltraFlavor { public: diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp index 2dd0f7a249f..02c9620009f 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_flavor.hpp @@ -83,8 +83,6 @@ class TranslatorFlavor { static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 7; // The total number of witness entities not including shifts. static constexpr size_t NUM_WITNESS_ENTITIES = 91; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = 177; static constexpr size_t NUM_WIRES_NON_SHIFTED = 1; static constexpr size_t NUM_SHIFTED_WITNESSES = 86; static constexpr size_t NUM_CONCATENATED = NUM_CONCATENATED_WIRES * CONCATENATION_GROUP_SIZE; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp index 49088ace522..fbc029c55b0 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/translator_verifier.cpp @@ -52,8 +52,8 @@ bool TranslatorVerifier::verify_proof(const HonkProof& proof) using Curve = typename Flavor::Curve; using PCS = typename Flavor::PCS; using Shplemini = ShpleminiVerifier_; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp index 7f5055fe9d7..3a09dd19619 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/decider_verifier.cpp @@ -40,8 +40,8 @@ template bool DeciderVerifier_::verify() using Curve = typename Flavor::Curve; using Shplemini = ShpleminiVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp index 0f9307bfd12..d8beb9b415c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/flavor.hpp @@ -97,8 +97,6 @@ class AvmFlavor { // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted static constexpr size_t NUM_ALL_ENTITIES = 813; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_ENTITIES; // Need to be templated for recursive verifier template diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp index 6af41ec7aad..9f2e6a04322 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/recursive_verifier.cpp @@ -78,8 +78,8 @@ AvmRecursiveVerifier_::AggregationObject AvmRecursiveVerifier_:: using RelationParams = ::bb::RelationParameters; using Transcript = typename Flavor::Transcript; using Shplemini = ::bb::ShpleminiVerifier_; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; transcript = std::make_shared(stdlib_proof); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp index 5a82de706b8..3a6c8e6da99 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm/generated/verifier.cpp @@ -45,8 +45,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; RelationParameters relation_parameters; diff --git a/barretenberg/cpp/src/barretenberg/vm2/generated/flavor.hpp b/barretenberg/cpp/src/barretenberg/vm2/generated/flavor.hpp index b74d954b275..243de435825 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/generated/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/vm2/generated/flavor.hpp @@ -82,8 +82,6 @@ class AvmFlavor { // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted static constexpr size_t NUM_ALL_ENTITIES = 466; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_ENTITIES; // Need to be templated for recursive verifier template diff --git a/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp b/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp index 5708f60727e..d90cc798f6a 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/generated/verifier.cpp @@ -45,8 +45,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; RelationParameters relation_parameters; diff --git a/barretenberg/cpp/src/barretenberg/vm2/tracegen/lib/lookup_into_sha256_params.hpp b/barretenberg/cpp/src/barretenberg/vm2/tracegen/lib/lookup_into_sha256_params.hpp deleted file mode 100644 index eeb1c38ce3c..00000000000 --- a/barretenberg/cpp/src/barretenberg/vm2/tracegen/lib/lookup_into_sha256_params.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include - -#include "barretenberg/vm2/tracegen/lib/lookup_builder.hpp" - -namespace bb::avm2::tracegen { - -template class LookupIntoSha256Params : public BaseLookupTraceBuilder { - private: - uint32_t find_in_dst(const std::array& tup) const override - { - // clk/row-index is the round constant for the SHA-256 compression algorithm. - const auto& [clk, _] = tup; - return static_cast(clk); - } -}; -} // namespace bb::avm2::tracegen diff --git a/barretenberg/cpp/src/barretenberg/vm2/tracegen_helper.cpp b/barretenberg/cpp/src/barretenberg/vm2/tracegen_helper.cpp index 51c4f8e4a26..48f21de77b5 100644 --- a/barretenberg/cpp/src/barretenberg/vm2/tracegen_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm2/tracegen_helper.cpp @@ -26,7 +26,6 @@ #include "barretenberg/vm2/tracegen/lib/lookup_builder.hpp" #include "barretenberg/vm2/tracegen/lib/lookup_into_bitwise.hpp" #include "barretenberg/vm2/tracegen/lib/lookup_into_indexed_by_clk.hpp" -#include "barretenberg/vm2/tracegen/lib/lookup_into_sha256_params.hpp" #include "barretenberg/vm2/tracegen/lib/permutation_builder.hpp" #include "barretenberg/vm2/tracegen/precomputed_trace.hpp" #include "barretenberg/vm2/tracegen/sha256_trace.hpp" @@ -199,7 +198,7 @@ TraceContainer AvmTraceGenHelper::generate_trace(EventsContainer&& events) std::make_unique>(), std::make_unique>(), std::make_unique>(), - std::make_unique>()); + std::make_unique>()); AVM_TRACK_TIME("tracegen/interactions", parallel_for(jobs_interactions.size(), [&](size_t i) { jobs_interactions[i]->process(trace); })); } diff --git a/barretenberg/sol/src/honk/BaseHonkVerifier.sol b/barretenberg/sol/src/honk/BaseHonkVerifier.sol index fc20594bddd..d6ad628b1de 100644 --- a/barretenberg/sol/src/honk/BaseHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseHonkVerifier.sol @@ -39,13 +39,22 @@ abstract contract BaseHonkVerifier is IVerifier { } // Errors + error ProofLengthWrong(); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); + // Number of field elements in a ultra honk proof + uint256 constant PROOF_SIZE = 443; + function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); function verify(bytes calldata proof, bytes32[] calldata publicInputs) public view override returns (bool) { + // Check the received proof is the expected size where each field element is 32 bytes + if (proof.length != PROOF_SIZE * 32) { + revert ProofLengthWrong(); + } + Honk.VerificationKey memory vk = loadVerificationKey(); Honk.Proof memory p = TranscriptLib.loadProof(proof); if (publicInputs.length != vk.publicInputsSize) { diff --git a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol index fee12422171..b93f6711741 100644 --- a/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol +++ b/barretenberg/sol/src/honk/BaseZKHonkVerifier.sol @@ -41,12 +41,16 @@ abstract contract BaseZKHonkVerifier is IVerifier { } // Errors + error ProofLengthWrong(); error PublicInputsLengthWrong(); error SumcheckFailed(); error ShpleminiFailed(); error GeminiChallengeInSubgroup(); error ConsistencyCheckFailed(); + // Number of field elements in a ultra honk zero knowledge proof + uint256 constant PROOF_SIZE = 494; + function loadVerificationKey() internal pure virtual returns (Honk.VerificationKey memory); function verify(bytes calldata proof, bytes32[] calldata publicInputs) @@ -55,6 +59,11 @@ abstract contract BaseZKHonkVerifier is IVerifier { override returns (bool verified) { + // Check the received proof is the expected size where each field element is 32 bytes + if (proof.length != PROOF_SIZE * 32) { + revert ProofLengthWrong(); + } + Honk.VerificationKey memory vk = loadVerificationKey(); Honk.ZKProof memory p = ZKTranscriptLib.loadProof(proof); diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index abe591bd113..709856b25af 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.74.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.73.0...barretenberg.js-v0.74.0) (2025-02-04) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.73.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.72.1...barretenberg.js-v0.73.0) (2025-02-01) @@ -24,7 +31,7 @@ ### Features -* Gaztec ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) +* Aztec Playground ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) * Lazy wasm pt.1 ([#11371](https://github.com/AztecProtocol/aztec-packages/issues/11371)) ([864bc6f](https://github.com/AztecProtocol/aztec-packages/commit/864bc6f34431dee17e76c476716821996d2ff9e5)) * Lazy wasm pt3 ([#11435](https://github.com/AztecProtocol/aztec-packages/issues/11435)) ([7068d05](https://github.com/AztecProtocol/aztec-packages/commit/7068d055d91a6e81e6fbb670e17c77ee209a1a80)) * UH recursion in the browser ([#11049](https://github.com/AztecProtocol/aztec-packages/issues/11049)) ([c3c04a4](https://github.com/AztecProtocol/aztec-packages/commit/c3c04a4cb92f0447431160d425bda66a997c0d66)) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 35cce9ccdd4..3ccd338750c 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,7 +1,7 @@ { "name": "@aztec/bb.js", "packageManager": "yarn@4.5.2", - "version": "0.73.0", + "version": "0.74.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/bb-pilcom/bb-pil-backend/templates/flavor.hpp.hbs b/bb-pilcom/bb-pil-backend/templates/flavor.hpp.hbs index cd6287ae75a..41478a97888 100644 --- a/bb-pilcom/bb-pil-backend/templates/flavor.hpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/flavor.hpp.hbs @@ -73,8 +73,6 @@ class AvmFlavor { static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for the unshifted and one for the shifted static constexpr size_t NUM_ALL_ENTITIES = {{len all_cols_and_shifts}}; - // The total number of witnesses including shifts and derived entities. - static constexpr size_t NUM_ALL_WITNESS_ENTITIES = NUM_WITNESS_ENTITIES + NUM_SHIFTED_ENTITIES; // Need to be templated for recursive verifier template diff --git a/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs index 79dac1b3ee5..dd5f3f112f2 100644 --- a/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/recursive_verifier.cpp.hbs @@ -78,8 +78,8 @@ AvmRecursiveVerifier_::AggregationObject AvmRecursiveVerifier_:: using RelationParams = ::bb::RelationParameters; using Transcript = typename Flavor::Transcript; using Shplemini = ::bb::ShpleminiVerifier_; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; transcript = std::make_shared(stdlib_proof); diff --git a/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs b/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs index 9f77f234bde..28a9894940b 100644 --- a/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs +++ b/bb-pilcom/bb-pil-backend/templates/verifier.cpp.hbs @@ -45,8 +45,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof, const std::vector; - using ClaimBatcher = Shplemini::ClaimBatcher; - using ClaimBatch = Shplemini::ClaimBatch; + using ClaimBatcher = ClaimBatcher_; + using ClaimBatch = ClaimBatcher::Batch; RelationParameters relation_parameters; diff --git a/docs/.gitignore b/docs/.gitignore index 2b2fad56010..67fcfa892b4 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -22,6 +22,6 @@ npm-debug.log* yarn-debug.log* yarn-error.log* -/docs/reference/developer_references/aztecjs -/docs/reference/developer_references/smart_contract_reference/aztec-nr +/docs/developers/reference/aztecjs +/docs/developers/reference/smart_contract_reference/aztec-nr test-results diff --git a/docs/.yarn/install-state.gz b/docs/.yarn/install-state.gz index f53abb6747e..decac804d7d 100644 Binary files a/docs/.yarn/install-state.gz and b/docs/.yarn/install-state.gz differ diff --git a/docs/HOW_WE_WRITE_DOCS.md b/docs/HOW_WE_WRITE_DOCS.md index f585953aa10..d81fe19a17a 100644 --- a/docs/HOW_WE_WRITE_DOCS.md +++ b/docs/HOW_WE_WRITE_DOCS.md @@ -1,12 +1,12 @@ # How we write docs -This doc covers the structure and tone of Aztec developer documentation. For the contribution guidelines, go [here](./CONTRIBUTING.md). Please keep in mind that this is constantly changing. +This doc covers the structure and tone of Aztec developer documentation. For the contribution guidelines, go [here](./CONTRIBUTING.md). Please keep in mind that this is constantly changing. ## Structure ### High level -Aztec docs are divided into two main sections - `Learn` and `Build`. +Aztec docs are divided into two main sections - `Learn` and `Build`. Anyone technical can read the `Learn` section, whereas only developers who are actively building or starting to build on Aztec will read the `Build` section. @@ -16,7 +16,7 @@ The `Build` section contains information that only developers need to know - thi ### Types of pages -The Aztec docs roughly follow the [Diataxis](https://diataxis.fr/) framework. It is recommended to read this website before contributing to the docs. +The Aztec docs roughly follow the [Diataxis](https://diataxis.fr/) framework. It is recommended to read this website before contributing to the docs. Every page will fall into **one type of doc**. If your contribution covers multiple types, you will need to split it into multiple pages. @@ -39,8 +39,8 @@ These are docs that developers can consult to know exact and succinct informatio ## Tone * Concise and informative - for example, rather than repeating information, write "to learn more, read ..." -* Friendly and empathetic - for example, "you do not have to worry about this yet" -* Simple and jardon-avoidant when possible +* Friendly and empathetic - for example, "you do not have to worry about this yet" +* Simple and jardon-avoidant when possible * Short sentences * Unopinionated language - we know things are exciting sometimes, but try not to tell the developer what they should be excited about @@ -85,4 +85,4 @@ The Aztec docs use a sidebar - https://docusaurus.io/docs/sidebar/items ## Indexing and Search -Typesense docs search - https://typesense.org/ +Algolia docs search - https://docusaurus.io/docs/search#algolia-index-configuration diff --git a/docs/deploy_preview.sh b/docs/deploy_preview.sh index 1e8066487bf..1153325203a 100755 --- a/docs/deploy_preview.sh +++ b/docs/deploy_preview.sh @@ -23,7 +23,7 @@ if [ -n "$PR_NUMBER" ]; then fi # Deploy and capture exit code and output -if ! DEPLOY_OUTPUT=$(yarn netlify deploy --dir $(pwd) --site aztec-docs-dev 2>&1); then +if ! DEPLOY_OUTPUT=$(yarn netlify deploy --site aztec-docs-dev 2>&1); then echo "Netlify deploy failed with error:" echo "$DEPLOY_OUTPUT" exit 1 diff --git a/docs/docs/reference/developer_references/common_errors/_category_.json b/docs/docs/aztec/concepts/accounts/_category_.json similarity index 51% rename from docs/docs/reference/developer_references/common_errors/_category_.json rename to docs/docs/aztec/concepts/accounts/_category_.json index d4521585c1b..2aae1b60db1 100644 --- a/docs/docs/reference/developer_references/common_errors/_category_.json +++ b/docs/docs/aztec/concepts/accounts/_category_.json @@ -1,6 +1,6 @@ { - "label": "Common Errors", - "position": 5, + "label": "Accounts", + "position": 2, "collapsible": true, "collapsed": true } diff --git a/docs/docs/aztec/concepts/accounts/index.md b/docs/docs/aztec/concepts/accounts/index.md index 4f29f273ecb..bfd8d6a2971 100644 --- a/docs/docs/aztec/concepts/accounts/index.md +++ b/docs/docs/aztec/concepts/accounts/index.md @@ -72,7 +72,7 @@ def entryPoint(payload): enqueueCall(to, data, value, gasLimit); ``` -Read more about how to write an account contract [here](../../../tutorials/codealong/contract_tutorials/write_accounts_contract.md). +Read more about how to write an account contract [here](../../../developers/tutorials/codealong/contract_tutorials/write_accounts_contract.md). ### Account contracts and wallets @@ -135,7 +135,7 @@ However, during a public function execution, it is not possible to retrieve a va These two patterns combined allow an account contract to answer whether an action `is_valid_impl` for a given user both in private and public contexts. -You can read more about authorizing actions with authorization witnesses on [this page](./authwit.md). +You can read more about authorizing actions with authorization witnesses on [this page](../advanced/authwit.md). :::info @@ -147,7 +147,7 @@ Transaction simulations in the PXE are not currently simulated, this is future w Aztec requires users to define [encryption and nullifying keys](./keys.md) that are needed for receiving and spending private notes. Unlike transaction signing, encryption and nullifying is enshrined at the protocol. This means that there is a single scheme used for encryption and nullifying. These keys are derived from a master public key. This master public key, in turn, is used when deterministically deriving the account's address. -A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of [`SharedMutable`](../../../reference/developer_references/smart_contract_reference/storage/shared_state.md#sharedmutable) to enable rotating these keys. +A side effect of committing to a master public key as part of the address is that _this key cannot be rotated_. While an account contract implementation could include methods for rotating the signing key, this is unfortunately not possible for encryption and nullifying keys (note that rotating nullifying keys also creates other challenges such as preventing double spends). We are exploring usage of [`SharedMutable`](../../../developers/reference/smart_contract_reference/storage/shared_state.md) to enable rotating these keys. NOTE: While we entertained the idea of abstracting note encryption, where account contracts would define an `encrypt` method that would use a user-defined scheme, there are two main reasons we decided against this. First is that this entailed that, in order to receive funds, a user had to first deploy their account contract, which is a major UX issue. Second, users could define malicious `encrypt` methods that failed in certain circumstances, breaking application flows that required them to receive a private note. While this issue already exists in Ethereum when transferring ETH (see the [king of the hill](https://coinsbench.com/27-king-ethernaut-da5021cd4aa6)), its impact is made worse in Aztec since any execution failure in a private function makes the entire transaction unprovable (ie it is not possible to catch errors in calls to other private functions), and furthermore because encryption is required for any private state (not just for transferring ETH). Nevertheless, both of these problems are solvable. Initialization can be worked around by embedding a commitment to the bytecode in the address and removing the need for actually deploying contracts before interacting with them, and the king of the hill issue can be mitigated by introducing a full private VM that allows catching reverts. As such, we may be able to abstract encryption in the future as well. diff --git a/docs/docs/aztec/concepts/accounts/keys.md b/docs/docs/aztec/concepts/accounts/keys.md index f4ae669db30..89b1687ddce 100644 --- a/docs/docs/aztec/concepts/accounts/keys.md +++ b/docs/docs/aztec/concepts/accounts/keys.md @@ -54,7 +54,7 @@ When it comes to notes encryption and decryption: ### Signing keys -Thanks to the native [account abstraction](../accounts#background/index.md), authorization logic can be implemented in an alternative way that is up to the developer (e.g. using Google authorization credentials, vanilla password logic or Face ID mechanism). In these cases, signing keys may not be relevant. +Thanks to the native [account abstraction](../accounts/index.md), authorization logic can be implemented in an alternative way that is up to the developer (e.g. using Google authorization credentials, vanilla password logic or Face ID mechanism). In these cases, signing keys may not be relevant. However if one wants to implement authorization logic containing signatures (e.g. ECDSA or Shnorr) they will need signing keys. Usually, an account contract will validate a signature of the incoming payload against a known signing public key. @@ -85,7 +85,7 @@ When it comes to storing the signing key in a private note, there are several de #### Using Shared Mutable state -By [Shared Mutable](../../../reference/developer_references/smart_contract_reference/storage/shared_state#sharedmutable) we mean privately readable publicly mutable state. +By [Shared Mutable](../../../developers/reference/smart_contract_reference/storage/shared_state.md#sharedmutable) we mean privately readable publicly mutable state. To make public state accessible privately, there is a delay window in public state updates. One needs this window to be able to generate proofs client-side. This approach would not generate additional nullifiers and commitments for each transaction while allowing the user to rotate their key. However, this causes every transaction to now have a time-to-live determined by the frequency of the mutable shared state, as well as imposing restrictions on how fast keys can be rotated due to minimum delays. @@ -123,7 +123,7 @@ App-siloed keys allow to minimize damage of potential key leaks as a leak of the App-siloed keys are derived from the corresponding master keys and the contract address. For example, for the app-siloed nullifier secret key: `nsk_app = hash(nsk_m, app_contract_address)`. -App-siloed keys [are derived](../storage/storage_slots#implementation/index.md) in PXE every time the user interacts with the application. +App-siloed keys [are derived](../advanced/storage/storage_slots.md#implementation) in PXE every time the user interacts with the application. App-siloed incoming viewing key also allows per-application auditability. A user may choose to disclose this key for a given application to an auditor or regulator (or for 3rd party interfaces, e.g. giving access to a block explorer to display my activity), as a means to reveal all their activity within that context, while retaining privacy across all other applications in the network. diff --git a/docs/docs/aztec/concepts/accounts/authwit.md b/docs/docs/aztec/concepts/advanced/authwit.md similarity index 95% rename from docs/docs/aztec/concepts/accounts/authwit.md rename to docs/docs/aztec/concepts/advanced/authwit.md index 307c07a0edb..fae1972c8eb 100644 --- a/docs/docs/aztec/concepts/accounts/authwit.md +++ b/docs/docs/aztec/concepts/advanced/authwit.md @@ -1,7 +1,7 @@ --- title: Authentication Witness (Authwit) tags: [accounts, authwit] -importance: 1 +sidebar_position: 2 keywords: [authwit, authentication witness, accounts] --- @@ -42,9 +42,9 @@ All of these issues have been discussed in the community for a while, and there Adopting ERC20 for Aztec is not as simple as it might seem because of private state. -If you recall from the [Hybrid State model](../storage/state_model/index.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. +If you recall from the [Hybrid State model](../storage/state_model.md), private state is generally only known by its owner and those they have shared it with. Because it relies on secrets, private state might be "owned" by a contract, but it needs someone with knowledge of these secrets to actually spend it. You might see where this is going. -If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](./keys.md). +If we were to implement the `approve` with an allowance in private, you might know the allowance, but unless you also know about the individual notes that make up the user's balances, it would be of no use to you! It is private after all. To spend the user's funds you would need to know the decryption key, see [keys for more](../accounts/keys.md). While this might sound limiting in what we can actually do, the main use of approvals have been for simplifying contract interactions that the user is doing. In the case of private transactions, this is executed on the user device, so it is not a blocker that the user need to tell the executor a secret - the user is the executor! @@ -140,4 +140,4 @@ We don't need to limit ourselves to the `transfer` function, we can use the same ### Next Steps -Check out the [developer documentation](../../../guides/developer_guides/smart_contracts/writing_contracts/authwit.md) to see how to implement this in your own contracts. +Check out the [developer documentation](../../../developers/guides/smart_contracts/writing_contracts/authwit.md) to see how to implement this in your own contracts. diff --git a/docs/docs/aztec/concepts/advanced/circuits/_category_.json b/docs/docs/aztec/concepts/advanced/circuits/_category_.json new file mode 100644 index 00000000000..611f5ed6919 --- /dev/null +++ b/docs/docs/aztec/concepts/advanced/circuits/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Circuits", + "position": 3, + "collapsible": true, + "collapsed": true +} diff --git a/docs/docs/aztec/concepts/circuits/index.md b/docs/docs/aztec/concepts/advanced/circuits/index.md similarity index 97% rename from docs/docs/aztec/concepts/circuits/index.md rename to docs/docs/aztec/concepts/advanced/circuits/index.md index 69b2e70499c..79f0a9aeaa1 100644 --- a/docs/docs/aztec/concepts/circuits/index.md +++ b/docs/docs/aztec/concepts/advanced/circuits/index.md @@ -1,6 +1,6 @@ --- title: Circuits -sidebar_position: 7 +sidebar_position: 2 tags: [protocol, circuits] --- @@ -53,7 +53,7 @@ In other words, since neither the EVM nor other rollups have rules for how to pr What kind of extra rules / checks does a rollup need, to enforce notions of private states and private functions? Stuff like: -- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [trees](../storage/trees/index.md)). +- "Perform state reads and writes using new tree structures which prevent tx linkability" (see [indexed merkle tree](../storage/indexed_merkle_tree.mdx). - "Hide which function was just executed, by wrapping it in a zk-snark" - "Hide all functions which were executed as part of this tx's stack trace, by wrapping the whole tx in a zk-snark" diff --git a/docs/docs/tutorials/examples/_category_.json b/docs/docs/aztec/concepts/advanced/circuits/kernels/_category_.json similarity index 63% rename from docs/docs/tutorials/examples/_category_.json rename to docs/docs/aztec/concepts/advanced/circuits/kernels/_category_.json index 29f159518ad..aa6ead3d71d 100644 --- a/docs/docs/tutorials/examples/_category_.json +++ b/docs/docs/aztec/concepts/advanced/circuits/kernels/_category_.json @@ -1,5 +1,5 @@ { - "label": "Smart Contract Examples", + "label": "Kernel Circuits", "position": 0, "collapsible": true, "collapsed": true diff --git a/docs/docs/aztec/concepts/circuits/kernels/private_kernel.md b/docs/docs/aztec/concepts/advanced/circuits/kernels/private_kernel.md similarity index 100% rename from docs/docs/aztec/concepts/circuits/kernels/private_kernel.md rename to docs/docs/aztec/concepts/advanced/circuits/kernels/private_kernel.md diff --git a/docs/docs/aztec/concepts/advanced/circuits/kernels/public_kernel.md b/docs/docs/aztec/concepts/advanced/circuits/kernels/public_kernel.md new file mode 100644 index 00000000000..a8b8945ffc0 --- /dev/null +++ b/docs/docs/aztec/concepts/advanced/circuits/kernels/public_kernel.md @@ -0,0 +1,6 @@ +--- +title: Public Kernel Circuit +tags: [protocol, circuits] +--- + +This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](../../../storage/state_model.md#public-state) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. diff --git a/docs/docs/aztec/concepts/circuits/rollup_circuits/index.md b/docs/docs/aztec/concepts/advanced/circuits/rollup_circuits/index.md similarity index 100% rename from docs/docs/aztec/concepts/circuits/rollup_circuits/index.md rename to docs/docs/aztec/concepts/advanced/circuits/rollup_circuits/index.md diff --git a/docs/docs/aztec/concepts/advanced/index.md b/docs/docs/aztec/concepts/advanced/index.md new file mode 100644 index 00000000000..c818c03e92e --- /dev/null +++ b/docs/docs/aztec/concepts/advanced/index.md @@ -0,0 +1,12 @@ +--- +title: Advanced Concepts +sidebar_position: 7 +tags: [protocol] +--- + +In this section, you'll learn about the more advanced concepts of the Aztec Network. It is not required to understand these in order to start building on Aztec. + +import DocCardList from '@theme/DocCardList'; + + + diff --git a/docs/docs/aztec/_category_.json b/docs/docs/aztec/concepts/advanced/storage/_category_.json similarity index 62% rename from docs/docs/aztec/_category_.json rename to docs/docs/aztec/concepts/advanced/storage/_category_.json index 22b47d59039..537ab73d1a0 100644 --- a/docs/docs/aztec/_category_.json +++ b/docs/docs/aztec/concepts/advanced/storage/_category_.json @@ -1,5 +1,5 @@ { - "label": "Aztec", + "label": "Advanced Storage Concepts", "position": 1, "collapsible": true, "collapsed": true diff --git a/docs/docs/aztec/concepts/storage/trees/indexed_merkle_tree.mdx b/docs/docs/aztec/concepts/advanced/storage/indexed_merkle_tree.mdx similarity index 99% rename from docs/docs/aztec/concepts/storage/trees/indexed_merkle_tree.mdx rename to docs/docs/aztec/concepts/advanced/storage/indexed_merkle_tree.mdx index 656b7bfd302..22e7ea7603b 100644 --- a/docs/docs/aztec/concepts/storage/trees/indexed_merkle_tree.mdx +++ b/docs/docs/aztec/concepts/advanced/storage/indexed_merkle_tree.mdx @@ -1,5 +1,7 @@ --- -title: Indexed Merkle Tree +title: Indexed Merkle Tree (Nullifier Tree) +tags: [storage, concepts, advanced] +sidebar_position: 2 --- import Image from "@theme/IdealImage"; @@ -48,7 +50,7 @@ Data is stored at the leaf index corresponding to its value. E.g. if I have a sp ## Problems introduced by using Sparse Merkle Trees for Nullifier Trees -While sparse Merkle Trees offer a simple and elegant solution, their implementation comes with some drawbacks. A sparse nullifier tree must have an index for $e \in \mathbb{F}_p$, which for the bn254 curve means that the sparse tree will need to have a depth of 254. +While sparse Merkle Trees offer a simple and elegant solution, their implementation comes with some drawbacks. A sparse nullifier tree must have an index for $e \in \mathbb{F}_p$, which for the bn254 curve means that the sparse tree will need to have a depth of 254. If you're familiar with hashing in circuits the alarm bells have probably started ringing. A tree of depth 254 means 254 hashes per membership proof. In routine nullifier insertions, a non membership check for a value is performed, then an insertion of said value. This amounts to two trips from leaf to root, hashing all the way up. This means that there are $254*2$ hashes per tree insertion. As the tree is sparse, insertions are random and must be performed in sequence. This means the number of hashes performed in the circuit scales linearly with the number of nullifiers being inserted. As a consequence number of constraints in a rollup circuit (where these checks are performed) will sky rocket, leading to long rollup proving times. diff --git a/docs/docs/aztec/concepts/storage/partial_notes.md b/docs/docs/aztec/concepts/advanced/storage/partial_notes.md similarity index 98% rename from docs/docs/aztec/concepts/storage/partial_notes.md rename to docs/docs/aztec/concepts/advanced/storage/partial_notes.md index ba5f7196f5f..5d223862d93 100644 --- a/docs/docs/aztec/concepts/storage/partial_notes.md +++ b/docs/docs/aztec/concepts/advanced/storage/partial_notes.md @@ -2,6 +2,7 @@ title: Partial Notes description: Describes how partial notes are used in Aztec tags: [notes, storage] +sidebar_position: 3 --- Partial notes are a concept that allows users to commit to an encrypted value, and allows a counterparty to update that value without knowing the specific details of the encrypted value. @@ -138,7 +139,7 @@ This is implemented by applying the `partial_note` attribute: #include_code UintNote noir-projects/aztec-nr/uint-note/src/uint_note.nr rust -Those `G_x` are generators that generated [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/generators.nr). Anyone can use them for separating different fields in a "partial note". +Those `G_x` are generators that generated [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-projects/aztec-nr/aztec/src/generators.nr). Anyone can use them for separating different fields in a "partial note". We can see the complete implementation of creating and completing partial notes in an Aztec contract in the `setup_refund` and `complete_refund` functions. diff --git a/docs/docs/aztec/concepts/storage/storage_slots.md b/docs/docs/aztec/concepts/advanced/storage/storage_slots.md similarity index 73% rename from docs/docs/aztec/concepts/storage/storage_slots.md rename to docs/docs/aztec/concepts/advanced/storage/storage_slots.md index d3121c645d9..2bfc1ef43b0 100644 --- a/docs/docs/aztec/concepts/storage/storage_slots.md +++ b/docs/docs/aztec/concepts/advanced/storage/storage_slots.md @@ -1,9 +1,14 @@ +--- +title: Storage Slots +tags: [storage, concepts, advanced] +sidebar_position: 1 +--- # Storage Slots ## Public State Slots -As mentioned in [State Model](../storage/state_model/index.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. +As mentioned in [State Model](../../storage/state_model.md), Aztec public state behaves similarly to public state on Ethereum from the point of view of the developer. Behind the scenes however, the storage is managed differently. As mentioned, public state has just one large sparse tree in Aztec - so we silo slots of public data by hashing it together with its contract address. The mental model is that we have a key-value store, where the siloed slot is the key, and the value is the data stored in that slot. You can think of the `real_storage_slot` identifying its position in the tree, and the `logical_storage_slot` identifying the position in the contract storage. @@ -11,13 +16,13 @@ The mental model is that we have a key-value store, where the siloed slot is the real_storage_slot = H(contract_address, logical_storage_slot) ``` -The siloing is performed by the [Kernel circuits](../circuits/index.md). +The siloing is performed by the [Kernel circuits](../circuits/kernels/private_kernel.md). For structs and arrays, we are logically using a similar storage slot computation to ethereum, e.g., as a struct with 3 fields would be stored in 3 consecutive slots. However, because the "actual" storage slot is computed as a hash of the contract address and the logical storage slot, the actual storage slot is not consecutive. ## Private State Slots -Private storage is a different beast. As you might remember from [Hybrid State Model](../storage/state_model/index.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree, called the note hash tree where each leaf is a commitment. Append-only means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that updates at a specific storage slot would leak information in the context of private state, even if the value is encrypted. That is not good privacy. +Private storage is a different beast. As you might remember from [Hybrid State Model](../../storage/state_model.md), private state is stored in encrypted logs and the corresponding private state commitments in append-only tree, called the note hash tree where each leaf is a commitment. Append-only means that leaves are never updated or deleted; instead a nullifier is emitted to signify that some note is no longer valid. A major reason we used this tree, is that updates at a specific storage slot would leak information in the context of private state, even if the value is encrypted. That is not good privacy. Following this, the storage slot as we know it doesn't really exist. The leaves of the note hashes tree are just commitments to content (think of it as a hash of its content). @@ -52,4 +57,4 @@ By doing this address-siloing at the kernel circuit we _force_ the inserted comm To ensure that nullifiers don't collide across contracts we also force this contract siloing at the kernel level. ::: -For an example of this see [developer documentation on storage](../../../reference/developer_references/smart_contract_reference/storage/index.md). +For an example of this see [developer documentation on storage](../../../../developers/reference/smart_contract_reference/storage/index.md). diff --git a/docs/docs/aztec/concepts/circuits/kernels/public_kernel.md b/docs/docs/aztec/concepts/circuits/kernels/public_kernel.md deleted file mode 100644 index c5466010908..00000000000 --- a/docs/docs/aztec/concepts/circuits/kernels/public_kernel.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Public Kernel Circuit -tags: [protocol, circuits] ---- - -This circuit is executed by a Sequencer, since only a Sequencer knows the current state of the [public data tree](../../storage/trees/index.md) at any time. A Sequencer might choose to delegate proof generation to the Prover pool. diff --git a/docs/docs/aztec/concepts/pxe/acir_simulator.md b/docs/docs/aztec/concepts/pxe/acir_simulator.md index 385e95c070b..c6bb4ac8c8d 100644 --- a/docs/docs/aztec/concepts/pxe/acir_simulator.md +++ b/docs/docs/aztec/concepts/pxe/acir_simulator.md @@ -20,7 +20,7 @@ Private functions can call other private functions and can request to call a pub ### Public Functions -Public functions are simulated and proved on the [sequencer](../../network/sequencer/index.md) side, and verified by the [public kernel circuit](../../concepts/circuits/kernels/public_kernel.md). +Public functions are simulated and proved on the sequencer side, and verified by the [public kernel circuit](../../concepts/advanced/circuits/kernels/public_kernel.md). They are run with the assistance of an oracle that provides any value read from the public state tree. diff --git a/docs/docs/aztec/concepts/pxe/index.md b/docs/docs/aztec/concepts/pxe/index.md index c5f5d0e5416..c82f3bcc97f 100644 --- a/docs/docs/aztec/concepts/pxe/index.md +++ b/docs/docs/aztec/concepts/pxe/index.md @@ -52,7 +52,7 @@ Until there are simulated simulations ([#9133](https://github.com/AztecProtocol/ ### Proof Generation -After simulation, the wallet calls `proveTx` on the PXE with all of the data generated during simulation and any [authentication witnesses](../accounts/authwit.md) (for allowing contracts to act on behalf of the users' account contract). +After simulation, the wallet calls `proveTx` on the PXE with all of the data generated during simulation and any [authentication witnesses](../advanced/authwit.md) (for allowing contracts to act on behalf of the users' account contract). Once proven, the wallet sends the transaction to the network and sends the transaction hash back to the application. @@ -108,5 +108,5 @@ Oracles are pieces of data that are injected into a smart contract function from To learn how to develop on top of the PXE, refer to these guides: -- [Run more than one PXE on your local machine](../../../guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md) -- [Use in-built oracles including oracles for arbitrary data](../../../guides/developer_guides/smart_contracts/writing_contracts/how_to_pop_capsules.md) +- [Run more than one PXE on your local machine](../../../developers/guides/local_env/run_more_than_one_pxe_sandbox.md) +- [Use in-built oracles including oracles for arbitrary data](../../../developers/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md) diff --git a/docs/docs/aztec/concepts/storage/_category_.json b/docs/docs/aztec/concepts/storage/_category_.json new file mode 100644 index 00000000000..18fc6d50b8c --- /dev/null +++ b/docs/docs/aztec/concepts/storage/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Storage", + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/docs/aztec/concepts/storage/index.md b/docs/docs/aztec/concepts/storage/index.md index 3e115ed8b44..d440a19d8d4 100644 --- a/docs/docs/aztec/concepts/storage/index.md +++ b/docs/docs/aztec/concepts/storage/index.md @@ -1,7 +1,7 @@ --- title: Storage description: How are storage slots derived for public and private state -sidebar_position: 2 +sidebar_position: 0 tags: [protocol, storage] --- diff --git a/docs/docs/aztec/concepts/storage/state_model/index.md b/docs/docs/aztec/concepts/storage/state_model.md similarity index 96% rename from docs/docs/aztec/concepts/storage/state_model/index.md rename to docs/docs/aztec/concepts/storage/state_model.md index 9aa78d92d3f..7fa650fc498 100644 --- a/docs/docs/aztec/concepts/storage/state_model/index.md +++ b/docs/docs/aztec/concepts/storage/state_model.md @@ -35,4 +35,4 @@ This is achieved with two main features: ## Further reading -Read more about how to leverage the Aztec state model in Aztec contracts [here](../../storage/index.md). +Read more about how to leverage the Aztec state model in Aztec contracts [here](../../../developers/reference/smart_contract_reference/storage/index.md). diff --git a/docs/docs/aztec/concepts/storage/state_model/public_vm.md b/docs/docs/aztec/concepts/storage/state_model/public_vm.md deleted file mode 100644 index dd2f5b2d0b1..00000000000 --- a/docs/docs/aztec/concepts/storage/state_model/public_vm.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Public VM ---- - -import Spec_Placeholder from '/components/snippet'; - - diff --git a/docs/docs/aztec/concepts/storage/trees/index.md b/docs/docs/aztec/concepts/storage/trees/index.md deleted file mode 100644 index 387a27dd87e..00000000000 --- a/docs/docs/aztec/concepts/storage/trees/index.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Trees ---- - -import Spec_Placeholder from '/components/snippet'; - - diff --git a/docs/docs/aztec/concepts/wallets/index.md b/docs/docs/aztec/concepts/wallets/index.md index 02b0f04fee9..013336faa8b 100644 --- a/docs/docs/aztec/concepts/wallets/index.md +++ b/docs/docs/aztec/concepts/wallets/index.md @@ -6,7 +6,7 @@ tags: [accounts] On this page we will cover the main responsibilities of a wallet in the Aztec network. -Refer to [writing an account contract](../../../tutorials/codealong/contract_tutorials/write_accounts_contract.md) for a tutorial on how to write a contract to back a user's account. +Refer to [writing an account contract](../../../developers/tutorials/codealong/contract_tutorials/write_accounts_contract.md) for a tutorial on how to write a contract to back a user's account. Go to [wallet architecture](./architecture.md) for an overview of its architecture and a reference on the interface a wallet must implement. @@ -22,7 +22,7 @@ The first step for any wallet is to let the user set up their [accounts](../acco A wallet must support at least one specific account contract implementation, which means being able to deploy such a contract, as well as interacting with it when sending transactions. Code-wise, this requires [implementing the `AccountContract` interface](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/account_contract/index.ts). -Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](../accounts/keys.md#complete-address) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. +Note that users must be able to receive funds in Aztec before deploying their account. A wallet should let a user generate a [deterministic complete address](../accounts/keys.md#address-keys) without having to interact with the network, so they can share it with others to receive funds. This requires that the wallet pins a specific contract implementation, its initialization arguments, a deployment salt, and a privacy key. These values yield a deterministic address, so when the account contract is actually deployed, it is available at the precalculated address. Once the account contract is deployed, the user can start sending transactions using it as the transaction origin. ## Transaction lifecycle diff --git a/docs/docs/aztec/glossary/call_types.md b/docs/docs/aztec/glossary/call_types.md index 0bd73fcfd41..e956f4374cf 100644 --- a/docs/docs/aztec/glossary/call_types.md +++ b/docs/docs/aztec/glossary/call_types.md @@ -144,7 +144,7 @@ aztec = { git = "https://github.com/AztecProtocol/aztec-packages/", tag = "#incl Even with the router contract achieving good privacy is hard. For example, if the value being checked against is unique and stored in the contract's public storage, it's then simple to find private transactions that are using that value in the enqueued public reads, and therefore link them to this contract. -For this reason it is encouraged to try to avoid public function calls and instead privately read [Shared State](../../reference/developer_references/smart_contract_reference/storage/shared_state.md) when possible. +For this reason it is encouraged to try to avoid public function calls and instead privately read [Shared State](../../developers/reference/smart_contract_reference/storage/shared_state.md) when possible. ### Public Execution diff --git a/docs/docs/aztec/concepts_overview.md b/docs/docs/aztec/index.md similarity index 92% rename from docs/docs/aztec/concepts_overview.md rename to docs/docs/aztec/index.md index 701e2e69b44..bb62dd08eec 100644 --- a/docs/docs/aztec/concepts_overview.md +++ b/docs/docs/aztec/index.md @@ -1,5 +1,5 @@ --- -title: Concepts Overview +title: Aztec Overview sidebar_position: 0 tags: [protocol] --- @@ -42,9 +42,9 @@ The PXE is unaware of the Public VM. And the Public VM is unaware of the PXE. Th ## Private and public state -Private state works with UTXOs, which are chunks of data that we call notes. To keep things private, notes are stored in an [append-only UTXO tree](./concepts/storage/trees/index.md), and a nullifier is created when notes are invalidated (aka deleted). Nullifiers are stored in their own [nullifier tree](./concepts/storage/trees/index.md). +Private state works with UTXOs, which are chunks of data that we call notes. To keep things private, notes are stored in an [append-only UTXO tree](./concepts/advanced/storage/indexed_merkle_tree.mdx), and a nullifier is created when notes are invalidated (aka deleted). Nullifiers are stored in their own [nullifier tree](./concepts/advanced/storage/indexed_merkle_tree.mdx). -Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a [public data tree](./concepts/storage/trees/index.md#public-state-tree). +Public state works similarly to other chains like Ethereum, behaving like a public ledger. Public data is stored in a public data tree. ![Public vs private state](../../static/img/public-and-private-state-diagram.png) @@ -79,7 +79,7 @@ Noir is a zero-knowledge domain specific language used for writing smart contrac ### Start coding
- +

Developer Getting Started Guide

@@ -104,15 +104,6 @@ Explore the Concepts for a deeper understanding into the components that make up
- - -

Protocol Circuits

-
- - Central to Aztec's operations are circuits in the core protocol and the developer-written Aztec.nr contracts - -
-

PXE (pronounced 'pixie')

@@ -149,4 +140,13 @@ Explore the Concepts for a deeper understanding into the components that make up
+ + +

Protocol Circuits

+
+ + Central to Aztec's operations are circuits in the core protocol and the developer-written Aztec.nr contracts + +
+
diff --git a/docs/docs/aztec/network/sequencer/index.md b/docs/docs/aztec/network/sequencer/index.md index 614f405daad..e541d1fdd54 100644 --- a/docs/docs/aztec/network/sequencer/index.md +++ b/docs/docs/aztec/network/sequencer/index.md @@ -1,6 +1,7 @@ --- title: Sequencer -tags: [protocol] +tags: [protocol, sequencer] +draft: true --- The sequencer is a module responsible for creating and publishing new rollup blocks. This involves fetching txs from the P2P pool, ordering them, executing any public functions, running them through the rollup circuits, assembling the L2 block, and posting it to the L1 rollup contract along with any contract deployment public data. diff --git a/docs/docs/aztec/network/sequencer/sequencer_selection.md b/docs/docs/aztec/network/sequencer/sequencer_selection.md index 9feb7710294..4fb9ad73664 100644 --- a/docs/docs/aztec/network/sequencer/sequencer_selection.md +++ b/docs/docs/aztec/network/sequencer/sequencer_selection.md @@ -1,6 +1,7 @@ --- title: Sequencer Selection -tags: [protocol] +tags: [protocol, sequencer] +draft: true --- ## Fernet diff --git a/docs/docs/aztec/roadmap/features_initial_ldt.md b/docs/docs/aztec/roadmap/features_initial_ldt.md index 9a43cb3dbd1..2ccd8036621 100644 --- a/docs/docs/aztec/roadmap/features_initial_ldt.md +++ b/docs/docs/aztec/roadmap/features_initial_ldt.md @@ -6,7 +6,7 @@ tags: [sandbox] The Aztec Sandbox is intended to provide developers with a lightweight and fast local node, running alongside a PXE. -You can learn more about running the Sandbox [here](../../reference/developer_references/sandbox_reference/index.md). +You can learn more about running the Sandbox [here](../../developers/reference/environment_reference/sandbox-reference.md). Developers should be able to quickly spin up local, emulated instances of an Ethereum blockchain and an Aztec encrypted rollup, and start deploying private contracts and submitting private txs. diff --git a/docs/docs/aztec/smart_contracts/contract_creation.md b/docs/docs/aztec/smart_contracts/contract_creation.md index 6872b582fb8..7947c8cad92 100644 --- a/docs/docs/aztec/smart_contracts/contract_creation.md +++ b/docs/docs/aztec/smart_contracts/contract_creation.md @@ -9,4 +9,4 @@ import Spec_Placeholder from '/components/snippet'; ## Further reading -To see how to deploy a contract in practice, check out the [dapp development tutorial](../../tutorials/codealong/js_tutorials/simple_dapp/index.md). +To see how to deploy a contract in practice, check out the [dapp development tutorial](../../developers/tutorials/codealong/js_tutorials/simple_dapp/index.md). diff --git a/docs/docs/aztec/smart_contracts/contract_structure.md b/docs/docs/aztec/smart_contracts/contract_structure.md index 79c7428faff..2889475b0dd 100644 --- a/docs/docs/aztec/smart_contracts/contract_structure.md +++ b/docs/docs/aztec/smart_contracts/contract_structure.md @@ -37,4 +37,4 @@ Here's a common layout for a basic Aztec.nr Contract project: ``` - See the vanilla Noir docs for [more info on packages](https://noir-lang.org/docs/noir/modules_packages_crates/crates_and_packages). -- You can review the structure of a complete contract in the NFT contract tutorial [here](../../tutorials/codealong/contract_tutorials/nft_contract.md). +- You can review the structure of a complete contract in the NFT contract tutorial [here](../../developers/tutorials/codealong/contract_tutorials/nft_contract.md). diff --git a/docs/docs/aztec/smart_contracts/functions/attributes.md b/docs/docs/aztec/smart_contracts/functions/attributes.md index 46ff05a666b..1de3b944a4e 100644 --- a/docs/docs/aztec/smart_contracts/functions/attributes.md +++ b/docs/docs/aztec/smart_contracts/functions/attributes.md @@ -6,13 +6,13 @@ tags: [functions] On this page you will learn about function attributes and macros. -If you are looking for a reference of function macros, go [here](../../../reference/developer_references/smart_contract_reference/macros.md). +If you are looking for a reference of function macros, go [here](../../../developers/reference/smart_contract_reference/macros.md). ## Private functions #[private] A private function operates on private information, and is executed by the user on their device. Annotate the function with the `#[private]` attribute to tell the compiler it's a private function. This will make the [private context](./context.md#the-private-context) available within the function's execution scope. The compiler will create a circuit to define this function. -`#[private]` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](../../../aztec/concepts/circuits/kernels/private_kernel.md). +`#[private]` is just syntactic sugar. At compile time, the Aztec.nr framework inserts code that allows the function to interact with the [kernel](../../../aztec/concepts/advanced/circuits/kernels/private_kernel.md). To help illustrate how this interacts with the internals of Aztec and its kernel circuits, we can take an example private function, and explore what it looks like after Aztec.nr's macro expansion. @@ -141,7 +141,7 @@ let storage = Storage::init(&mut context); ## Constrained `view` Functions #[view] -The `#[view]` attribute is used to define constrained view functions in Aztec contracts. These functions are similar to view functions in Solidity, in that they are read-only and do not modify the contract's state. They are similar to the [`unconstrained`](#unconstrained-functions-aztecunconstrained) keyword but are executed in a constrained environment. It is not possible to update state within an `#[view]` function. +The `#[view]` attribute is used to define constrained view functions in Aztec contracts. These functions are similar to view functions in Solidity, in that they are read-only and do not modify the contract's state. They are similar to the [`unconstrained`](#unconstrained-functions) keyword but are executed in a constrained environment. It is not possible to update state within an `#[view]` function. This means the results of these functions are verifiable and can be trusted, as they are part of the proof generation and verification process. This is unlike unconstrained functions, where results are provided by the PXE and are not verified. @@ -159,7 +159,7 @@ This is used to designate functions as initializers (or constructors) for an Azt Key things to keep in mind: - A contract can have multiple initializer functions defined, but only one initializer function should be called for the lifetime of a contract instance -- Other functions in the contract will have an initialization check inserted, ie they cannot be called until the contract is initialized, unless they are marked with [`#[noinitcheck]`](#aztecnoinitcheck) +- Other functions in the contract will have an initialization check inserted, ie they cannot be called until the contract is initialized, unless they are marked with [`#[noinitcheck]`](#noinitcheck) ## #[noinitcheck] @@ -167,7 +167,7 @@ In normal circumstances, all functions in an Aztec contract (except initializers When a function is annotated with `#[noinitcheck]`: -- The Aztec macro processor skips the [insertion of the initialization check](#initializer-functions-aztecinitializer) for this specific function +- The Aztec macro processor skips the [insertion of the initialization check](#initializer-functions-initializer) for this specific function - The function can be called at any time, even if the contract hasn't been initialized yet ## `Internal` functions #[internal] @@ -358,7 +358,7 @@ Key things to keep in mind: ## Further reading -- [Macros reference](../../../reference/developer_references/smart_contract_reference/macros.md) +- [Macros reference](../../../developers/reference/smart_contract_reference/macros.md) - [How do macros work](./attributes.md) diff --git a/docs/docs/aztec/smart_contracts/functions/context.md b/docs/docs/aztec/smart_contracts/functions/context.md index 346e822a25a..fec4eca1aed 100644 --- a/docs/docs/aztec/smart_contracts/functions/context.md +++ b/docs/docs/aztec/smart_contracts/functions/context.md @@ -6,7 +6,7 @@ tags: [functions, context] ## What is the context -The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../concepts/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of its side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. +The context is an object that is made available within every function in `Aztec.nr`. As mentioned in the [kernel circuit documentation](../../concepts/advanced/circuits/kernels/private_kernel.md). At the beginning of a function's execution, the context contains all of the kernel information that application needs to execute. During the lifecycle of a transaction, the function will update the context with each of its side effects (created notes, nullifiers etc.). At the end of a function's execution the mutated context is returned to the kernel to be checked for validity. Behind the scenes, Aztec.nr will pass data the kernel needs to and from a circuit, this is abstracted away from the developer. In a developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. diff --git a/docs/docs/aztec/smart_contracts/functions/function_transforms.md b/docs/docs/aztec/smart_contracts/functions/function_transforms.md index c87aeda95c1..67a22b36403 100644 --- a/docs/docs/aztec/smart_contracts/functions/function_transforms.md +++ b/docs/docs/aztec/smart_contracts/functions/function_transforms.md @@ -12,7 +12,7 @@ Below, we go more into depth of what is happening under the hood when you create When you define a function in an Aztec contract, it undergoes several transformations when it is compiled. These transformations prepare the function for execution. These transformations include: - [Creating a context for the function](#context-creation) -- [Handling function inputs](#input-handling) +- [Handling function inputs](#private-and-public-input-injection) - [Processing return values](#return-value-handling) - [Computing note hashes and nullifiers](#computing-note-hash-and-nullifier) - [Generating function signatures](#function-signature-generation) @@ -192,7 +192,7 @@ fn compute_fn_signature_hash(fn_name: &str, parameters: &[Type]) -> u32 { - A string representation of the function is created, including the function name and parameter types - This signature string is then hashed using Keccak-256 -- The first 4 bytes of the resulting hash are converted to a u32 integer +- The first 4 bytes of the resulting hash are coverted to a u32 integer ### Integration into contract interface @@ -270,8 +270,8 @@ struct transfer_abi { Contract artifacts are important because: - They provide a machine-readable description of the contract -- They can be used to generate bindings for interacting with the contract (read [here](../../../guides/developer_guides/smart_contracts/how_to_compile_contract.md) to learn how to create TypeScript bindings) +- They can be used to generate bindings for interacting with the contract (read [here](../../../developers/guides/smart_contracts/how_to_compile_contract.md) to learn how to create TypeScript bindings) - They help decode function return values in the simulator ## Further reading -- [Function attributes and macros](./attributes.md) +- [Function attributes and macros](./attributes.md) \ No newline at end of file diff --git a/docs/docs/aztec/smart_contracts/functions/index.md b/docs/docs/aztec/smart_contracts/functions/index.md index 72a502f8050..b0bffb31858 100644 --- a/docs/docs/aztec/smart_contracts/functions/index.md +++ b/docs/docs/aztec/smart_contracts/functions/index.md @@ -3,9 +3,9 @@ title: Defining Functions tags: [functions] --- -Functions serve as the building blocks of smart contracts. Functions can be either **public**, ie they are publicly available for anyone to see and can directly interact with public state, or **private**, meaning they are executed completely client-side in the [PXE](../../concepts/pxe/index.md). Read more about how private functions work [here](./attributes.md#private-functions). +Functions serve as the building blocks of smart contracts. Functions can be either **public**, ie they are publicly available for anyone to see and can directly interact with public state, or **private**, meaning they are executed completely client-side in the [PXE](../../concepts/pxe/index.md). Read more about how private functions work [here](./attributes.md#private-functions-private). -For a more practical guide of using multiple types of functions, follow the [NFT tutorial](../../../tutorials/codealong/contract_tutorials/nft_contract.md). +For a more practical guide of using multiple types of functions, follow the [NFT tutorial](../../../developers/tutorials/codealong/contract_tutorials/nft_contract.md). Currently, any function is "mutable" in the sense that it might alter state. However, we also support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). @@ -22,8 +22,8 @@ There are also special oracle functions, which can get data from outside of the ## Learn more about functions - [How function visibility works in Aztec](./visibility.md) -- How to write an [initializer function](../../../guides/developer_guides/smart_contracts/writing_contracts/initializers.md) +- How to write an [initializer function](../../../developers/guides/smart_contracts/writing_contracts/initializers.md) - [Oracles](../oracles/index.md) and how Aztec smart contracts might use them - [How functions work under the hood](./attributes.md) -Find a function macros reference [here](../../../reference/developer_references/smart_contract_reference/macros.md) +Find a function macros reference [here](../../../developers/reference/smart_contract_reference/macros.md) diff --git a/docs/docs/aztec/smart_contracts/functions/visibility.md b/docs/docs/aztec/smart_contracts/functions/visibility.md index 599ce9818b0..006891f75c3 100644 --- a/docs/docs/aztec/smart_contracts/functions/visibility.md +++ b/docs/docs/aztec/smart_contracts/functions/visibility.md @@ -6,7 +6,7 @@ tags: [functions] In Aztec there are multiple different types of visibility that can be applied to functions. Namely we have `data visibility` and `function visibility`. This page explains these types of visibility. -For a practical guide of using multiple types of data and function visibility, follow the [NFT tutorial](../../../tutorials/codealong/contract_tutorials/nft_contract.md). +For a practical guide of using multiple types of data and function visibility, follow the [NFT tutorial](../../../developers/tutorials/codealong/contract_tutorials/nft_contract.md). ### Data Visibility diff --git a/docs/docs/aztec/smart_contracts/oracles/index.md b/docs/docs/aztec/smart_contracts/oracles/index.md index bd2f2ddc0a5..c12afb6325c 100644 --- a/docs/docs/aztec/smart_contracts/oracles/index.md +++ b/docs/docs/aztec/smart_contracts/oracles/index.md @@ -5,7 +5,7 @@ tags: [functions, oracles] This page goes over what oracles are in Aztec and how they work. -Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](../../../guides/developer_guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). +Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](../../../developers/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). An oracle is something that allows us to get data from the outside world into our contracts. The most widely-known types of oracles in blockchain systems are probably Chainlink price feeds, which allow us to get the price of an asset in USD taking non-blockchain data into account. @@ -14,7 +14,7 @@ While this is one type of oracle, the more general oracle, allows us to get any **Why is this useful? Why don't just pass them as input parameters?** In the world of EVM, you would just read the values directly from storage and call it a day. However, when we are working with circuits for private execution, this becomes more tricky as you cannot just read the storage directly from your state tree, because there are only commitments (e.g. hashes) there. The pre-images (content) of your commitments need to be provided to the function to prove that you actually allowed to modify them. -If we fetch the notes using an oracle call, we can keep the function signature independent of the underlying data and make it easier to use. A similar idea, applied to the authentication mechanism is used for the Authentication Witnesses that allow us to have a single function signature for any wallet implementation, see [AuthWit](../../concepts/accounts/authwit.md) for more information on this. +If we fetch the notes using an oracle call, we can keep the function signature independent of the underlying data and make it easier to use. A similar idea, applied to the authentication mechanism is used for the Authentication Witnesses that allow us to have a single function signature for any wallet implementation, see [AuthWit](../../concepts/advanced/authwit.md) for more information on this. Oracles introduce **non-determinism** into a circuit, and thus are `unconstrained`. It is important that any information that is injected into a circuit through an oracle is later constrained for correctness. Otherwise, the circuit will be **under-constrained** and potentially insecure! @@ -23,7 +23,7 @@ Oracles introduce **non-determinism** into a circuit, and thus are `unconstraine ## Inbuilt oracles -- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/debug_log.nr) - Provides a couple of debug functions that can be used to log information to the console. Read more about debugging [here](../../../reference/developer_references/debugging.md). +- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/debug_log.nr) - Provides a couple of debug functions that can be used to log information to the console. Read more about debugging [here](../../../developers/reference/debugging/index.md). - [`auth_witness`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth_witness.nr) - Provides a way to fetch the authentication witness for a given address. This is useful when building account contracts to support approve-like functionality. - [`get_l1_to_l2_message`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr) - Useful for application that receive messages from L1 to be consumed on L2, such as token bridges or other cross-chain applications. - [`notes`](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/aztec/src/oracle/notes.nr) - Provides a lot of functions related to notes, such as fetches notes from storage etc, used behind the scenes for value notes and other pre-build note implementations. @@ -31,4 +31,4 @@ Oracles introduce **non-determinism** into a circuit, and thus are `unconstraine Find a full list [on GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr/aztec/src/oracle). -Please note that it is **not** possible to write a custom oracle for your dapp. Oracles are implemented in the PXE, so all users of your dapp would have to use a PXE service with your custom oracle included. If you want to inject some arbitrary data that does not have a dedicated oracle, you can use [popCapsule](../../../guides/developer_guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). +Please note that it is **not** possible to write a custom oracle for your dapp. Oracles are implemented in the PXE, so all users of your dapp would have to use a PXE service with your custom oracle included. If you want to inject some arbitrary data that does not have a dedicated oracle, you can use [popCapsule](../../../developers/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md). diff --git a/docs/docs/aztec/smart_contracts_overview.md b/docs/docs/aztec/smart_contracts_overview.md index 234467d06e7..cd6ac1e5c39 100644 --- a/docs/docs/aztec/smart_contracts_overview.md +++ b/docs/docs/aztec/smart_contracts_overview.md @@ -25,4 +25,4 @@ There are no plans for EVM compatibility or to support Solidity in Aztec. The pr ## Further reading -Jump in and write your first smart contract [here](../tutorials/codealong/contract_tutorials/counter_contract.md) +Jump in and write your first smart contract [here](../developers/tutorials/codealong/contract_tutorials/counter_contract.md) diff --git a/docs/docs/aztec.md b/docs/docs/building_in_public.md similarity index 98% rename from docs/docs/aztec.md rename to docs/docs/building_in_public.md index 1f53886812d..627e9d2b65e 100644 --- a/docs/docs/aztec.md +++ b/docs/docs/building_in_public.md @@ -1,6 +1,7 @@ --- title: Building in Public sidebar_position: 0 +id: building_in_public --- import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; diff --git a/docs/docs/guides/getting_started.md b/docs/docs/developers/getting_started.md similarity index 99% rename from docs/docs/guides/getting_started.md rename to docs/docs/developers/getting_started.md index 1e1eafa8750..9f552ce4e65 100644 --- a/docs/docs/guides/getting_started.md +++ b/docs/docs/developers/getting_started.md @@ -226,7 +226,7 @@ Simulation result: 25n Now you have a development network running, so you're ready to start coding your first app with Aztec.nr and Aztec.js!
- +

Write your first contract

diff --git a/docs/docs/guides/_category_.json b/docs/docs/developers/guides/_category_.json similarity index 100% rename from docs/docs/guides/_category_.json rename to docs/docs/developers/guides/_category_.json diff --git a/docs/docs/guides/developer_guides/getting_started/_category_.json b/docs/docs/developers/guides/getting_started/_category_.json similarity index 100% rename from docs/docs/guides/developer_guides/getting_started/_category_.json rename to docs/docs/developers/guides/getting_started/_category_.json diff --git a/docs/docs/guides/developer_guides/getting_started/codespaces.md b/docs/docs/developers/guides/getting_started/codespaces.md similarity index 100% rename from docs/docs/guides/developer_guides/getting_started/codespaces.md rename to docs/docs/developers/guides/getting_started/codespaces.md diff --git a/docs/docs/guides/developer_guides/js_apps/_category_.json b/docs/docs/developers/guides/js_apps/_category_.json similarity index 100% rename from docs/docs/guides/developer_guides/js_apps/_category_.json rename to docs/docs/developers/guides/js_apps/_category_.json diff --git a/docs/docs/guides/developer_guides/js_apps/authwit.md b/docs/docs/developers/guides/js_apps/authwit.md similarity index 98% rename from docs/docs/guides/developer_guides/js_apps/authwit.md rename to docs/docs/developers/guides/js_apps/authwit.md index 92dd49dc677..4392befc977 100644 --- a/docs/docs/guides/developer_guides/js_apps/authwit.md +++ b/docs/docs/developers/guides/js_apps/authwit.md @@ -5,7 +5,7 @@ tags: [accounts, authwit] This page assumes you have authwit set up correctly in your contract. To learn how to do that, [go here](../smart_contracts/writing_contracts/authwit.md). -For an introduction to authentication witnesses on Aztec, [read this explainer](../../../aztec/concepts/accounts/authwit.md). +For an introduction to authentication witnesses on Aztec, [read this explainer](../../../aztec/concepts/advanced/authwit.md). ## Import libraries @@ -117,5 +117,5 @@ If you created an arbitrary message, you would replace the first param struct wi ## Further reading -- [An explainer of authentication witnesses](../../../aztec/concepts/accounts/authwit.md) +- [An explainer of authentication witnesses](../../../aztec/concepts/advanced/authwit.md) - [Authwits in Aztec.nr](../smart_contracts/writing_contracts/authwit.md) diff --git a/docs/docs/guides/developer_guides/js_apps/call_view_function.md b/docs/docs/developers/guides/js_apps/call_view_function.md similarity index 100% rename from docs/docs/guides/developer_guides/js_apps/call_view_function.md rename to docs/docs/developers/guides/js_apps/call_view_function.md diff --git a/docs/docs/guides/developer_guides/js_apps/create_account.md b/docs/docs/developers/guides/js_apps/create_account.md similarity index 100% rename from docs/docs/guides/developer_guides/js_apps/create_account.md rename to docs/docs/developers/guides/js_apps/create_account.md diff --git a/docs/docs/guides/developer_guides/js_apps/deploy_contract.md b/docs/docs/developers/guides/js_apps/deploy_contract.md similarity index 100% rename from docs/docs/guides/developer_guides/js_apps/deploy_contract.md rename to docs/docs/developers/guides/js_apps/deploy_contract.md diff --git a/docs/docs/guides/developer_guides/js_apps/send_transaction.md b/docs/docs/developers/guides/js_apps/send_transaction.md similarity index 100% rename from docs/docs/guides/developer_guides/js_apps/send_transaction.md rename to docs/docs/developers/guides/js_apps/send_transaction.md diff --git a/docs/docs/guides/developer_guides/js_apps/test.md b/docs/docs/developers/guides/js_apps/test.md similarity index 84% rename from docs/docs/guides/developer_guides/js_apps/test.md rename to docs/docs/developers/guides/js_apps/test.md index 19f10a7c56d..8c3f0d1a9c0 100644 --- a/docs/docs/guides/developer_guides/js_apps/test.md +++ b/docs/docs/developers/guides/js_apps/test.md @@ -61,7 +61,7 @@ This debug information will be populated in the transaction receipt. You can log #include_code debug /yarn-project/end-to-end/src/e2e_token_contract/private_transfer_recursion.test.ts typescript -You can also log directly from Aztec contracts. Read [this guide](../../../reference/developer_references/debugging.md#logging-in-aztecnr) for some more information. +You can also log directly from Aztec contracts. Read [this guide](../../reference/debugging/index.md#logging-in-aztecnr) for some more information. ### Examples @@ -101,13 +101,13 @@ WARN Error processing tx 06dc87c4d64462916ea58426ffcfaf20017880b353c9ec3e0f0ee5f We can check private or public state directly rather than going through view-only methods, as we did in the initial example by calling `token.methods.balance().simulate()`. -To query storage directly, you'll need to know the slot you want to access. This can be checked in the [contract's `Storage` definition](../../../reference/developer_references/smart_contract_reference/storage/index.md) directly for most data types. However, when it comes to mapping types, as in most EVM languages, we'll need to calculate the slot for a given key. To do this, we'll use the [`CheatCodes`](../../../reference/developer_references/sandbox_reference/cheat_codes.md) utility class: +To query storage directly, you'll need to know the slot you want to access. This can be checked in the [contract's `Storage` definition](../../reference/smart_contract_reference/storage/index.md) directly for most data types. However, when it comes to mapping types, as in most EVM languages, we'll need to calculate the slot for a given key. To do this, we'll use the [`CheatCodes`](../../reference/environment_reference/cheat_codes.md) utility class: #include_code calc-slot /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript #### Querying private state -Private state in the Aztec is represented via sets of [private notes](../../../aztec/concepts/storage/state_model/index.md#private-state). We can query the Private Execution Environment (PXE) for all notes encrypted for a given user in a contract slot. For example, this gets all notes encrypted for the `owner` user that are stored on the token contract address and on the slot that was calculated earlier. To calculate the actual balance, it extracts the `value` of each note, which is the first element, and sums them up. +Private state in the Aztec is represented via sets of [private notes](../../../aztec/concepts/storage/state_model.md#private-state). We can query the Private Execution Environment (PXE) for all notes encrypted for a given user in a contract slot. For example, this gets all notes encrypted for the `owner` user that are stored on the token contract address and on the slot that was calculated earlier. To calculate the actual balance, it extracts the `value` of each note, which is the first element, and sums them up. #include_code private-storage /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript @@ -129,12 +129,12 @@ We can query the PXE for the public logs emitted in the block where our transact ## Cheats -The [`CheatCodes`](../../../reference/developer_references/sandbox_reference/cheat_codes.md) class, which we used for [calculating the storage slot above](#querying-state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. +The [`CheatCodes`](../../reference/environment_reference/cheat_codes.md) class, which we used for [calculating the storage slot above](#querying-state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. ### Set next block timestamp Since the rollup time is dependent on what "slot" the block is included in, time can be progressed by progressing slots. -The duration of a slot is available by calling `getSlotDuration()` on the Rollup (code in Leonidas.sol). +The duration of a slot is available by calling `getSlotDuration()` on the Rollup (code in Rollup.sol). You can then use the `warp` function on the EthCheatCodes to progress the underlying chain. @@ -146,5 +146,5 @@ You can then use the `warp` function on the EthCheatCodes to progress the underl - [How to send a transactions in Aztec.js](./send_transaction.md) - [How to deploy a contract in Aztec.js](./deploy_contract.md) - [How to create an account in Aztec.js](./create_account.md) -- [Cheat codes](../../../reference/developer_references/sandbox_reference/cheat_codes.md) +- [Cheat codes](../../reference/environment_reference/cheat_codes.md) - [How to compile a contract](../smart_contracts/how_to_compile_contract.md). diff --git a/docs/docs/guides/developer_guides/local_env/_category_.json b/docs/docs/developers/guides/local_env/_category_.json similarity index 100% rename from docs/docs/guides/developer_guides/local_env/_category_.json rename to docs/docs/developers/guides/local_env/_category_.json diff --git a/docs/docs/guides/developer_guides/local_env/cloning_a_box.md b/docs/docs/developers/guides/local_env/cloning_a_box.md similarity index 100% rename from docs/docs/guides/developer_guides/local_env/cloning_a_box.md rename to docs/docs/developers/guides/local_env/cloning_a_box.md diff --git a/docs/docs/guides/developer_guides/local_env/creating_schnorr_accounts.md b/docs/docs/developers/guides/local_env/creating_schnorr_accounts.md similarity index 96% rename from docs/docs/guides/developer_guides/local_env/creating_schnorr_accounts.md rename to docs/docs/developers/guides/local_env/creating_schnorr_accounts.md index b45b653b7f9..6e88e456a22 100644 --- a/docs/docs/guides/developer_guides/local_env/creating_schnorr_accounts.md +++ b/docs/docs/developers/guides/local_env/creating_schnorr_accounts.md @@ -65,4 +65,4 @@ Once this has completed, the L2 block is retrieved and pulled down to the PXE so ## Next Steps -Check out our section on [Writing your own Account Contract](../../../tutorials/codealong/contract_tutorials/write_accounts_contract.md) leveraging our account abstraction. +Check out our section on [Writing your own Account Contract](../../tutorials/codealong/contract_tutorials/write_accounts_contract.md) leveraging our account abstraction. diff --git a/docs/docs/guides/developer_guides/local_env/installing_noir_lsp.md b/docs/docs/developers/guides/local_env/installing_noir_lsp.md similarity index 100% rename from docs/docs/guides/developer_guides/local_env/installing_noir_lsp.md rename to docs/docs/developers/guides/local_env/installing_noir_lsp.md diff --git a/docs/docs/guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md b/docs/docs/developers/guides/local_env/run_more_than_one_pxe_sandbox.md similarity index 95% rename from docs/docs/guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md rename to docs/docs/developers/guides/local_env/run_more_than_one_pxe_sandbox.md index d937f6f5f13..574fbd492d2 100644 --- a/docs/docs/guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md +++ b/docs/docs/developers/guides/local_env/run_more_than_one_pxe_sandbox.md @@ -42,4 +42,4 @@ You should see something like this: Aztec Server listening on port 8080 ``` -You can learn more about custom commands in the [sandbox reference](../../../reference/developer_references/sandbox_reference/sandbox-reference.md). +You can learn more about custom commands in the [sandbox reference](../../reference/environment_reference/sandbox-reference.md). diff --git a/docs/docs/guides/developer_guides/local_env/sandbox_proving.md b/docs/docs/developers/guides/local_env/sandbox_proving.md similarity index 94% rename from docs/docs/guides/developer_guides/local_env/sandbox_proving.md rename to docs/docs/developers/guides/local_env/sandbox_proving.md index c6fd869a971..e84a1bd914e 100644 --- a/docs/docs/guides/developer_guides/local_env/sandbox_proving.md +++ b/docs/docs/developers/guides/local_env/sandbox_proving.md @@ -46,12 +46,12 @@ You can enable proving on a per-transaction basis using the `aztec-wallet` CLI b PXE_PROVER_ENABLED=1 aztec-wallet create-account -a test ``` -Check the [Quickstart](../../getting_started.md) for a refresher on how to send transactions using `aztec-wallet` or check the [reference here](../../../reference/developer_references/cli_wallet_reference.md) +Check the [Quickstart](../../getting_started.md) for a refresher on how to send transactions using `aztec-wallet` or check the [reference here](../../reference/environment_reference/cli_wallet_reference.md) Note that you do not need to restart the sandbox in order to start sending proven transactions. You can optionally set this for one-off transactions. If this is the first time you are sending transactions with proving enabled, it will take a while to download a CRS file (which is several MBs) that is required for proving. :::note -You can also profile your transactions to get gate count, if you don't want to prove your transactions but check how many constraints it is. Follow the [guide here](../../developer_guides/smart_contracts/profiling_transactions.md) +You can also profile your transactions to get gate count, if you don't want to prove your transactions but check how many constraints it is. Follow the [guide here](../../guides/smart_contracts/profiling_transactions.md) ::: diff --git a/docs/docs/guides/developer_guides/local_env/versions-updating.md b/docs/docs/developers/guides/local_env/versions-updating.md similarity index 98% rename from docs/docs/guides/developer_guides/local_env/versions-updating.md rename to docs/docs/developers/guides/local_env/versions-updating.md index 9e90f47102c..f3a77b0abc2 100644 --- a/docs/docs/guides/developer_guides/local_env/versions-updating.md +++ b/docs/docs/developers/guides/local_env/versions-updating.md @@ -94,7 +94,7 @@ cd your/aztec/project aztec update . --contract src/contract1 --contract src/contract2 ``` -The sandbox must be running for the update command to work. Make sure it is [installed and running](../../../reference/developer_references/sandbox_reference/sandbox-reference.md). +The sandbox must be running for the update command to work. Make sure it is [installed and running](../../reference/environment_reference/sandbox-reference.md). Follow [updating Aztec.nr packages](#updating-aztecnr-packages) and [updating JavaScript packages](#updating-aztecjs-packages) guides. diff --git a/docs/docs/guides/developer_guides/smart_contracts/_category_.json b/docs/docs/developers/guides/smart_contracts/_category_.json similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/_category_.json rename to docs/docs/developers/guides/smart_contracts/_category_.json diff --git a/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md b/docs/docs/developers/guides/smart_contracts/how_to_compile_contract.md similarity index 98% rename from docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md rename to docs/docs/developers/guides/smart_contracts/how_to_compile_contract.md index df41a986f68..ceec6fcbd5a 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/how_to_compile_contract.md +++ b/docs/docs/developers/guides/smart_contracts/how_to_compile_contract.md @@ -8,7 +8,7 @@ Once you have written a contract in Aztec.nr, you will need to compile it into a In this guide we will cover how to do so, both using the `aztec-nargo` command and programmatically. -We'll also cover how to generate a helper [TypeScript interface](#typescript-interfaces) and an [Aztec.nr interface](#noir-interfaces) for easily interacting with your contract from your typescript app and from other Aztec.nr contracts, respectively. +We'll also cover how to generate a helper [TypeScript interface](#typescript-interfaces) and an [Aztec.nr interface](#aztecnr-interfaces) for easily interacting with your contract from your typescript app and from other Aztec.nr contracts, respectively. ## Compile using aztec-nargo @@ -444,7 +444,7 @@ export class TokenContract extends ContractBase { } ``` -Read more about interacting with contracts using `aztec.js` [by following this tutorial](../../../tutorials/codealong/js_tutorials/aztecjs-getting-started.md). +Read more about interacting with contracts using `aztec.js` [by following this tutorial](../../tutorials/codealong/js_tutorials/aztecjs-getting-started.md). ### Aztec.nr interfaces diff --git a/docs/docs/guides/developer_guides/smart_contracts/how_to_deploy_contract.md b/docs/docs/developers/guides/smart_contracts/how_to_deploy_contract.md similarity index 93% rename from docs/docs/guides/developer_guides/smart_contracts/how_to_deploy_contract.md rename to docs/docs/developers/guides/smart_contracts/how_to_deploy_contract.md index c6f7e9e57b4..8ff26d81582 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/how_to_deploy_contract.md +++ b/docs/docs/developers/guides/smart_contracts/how_to_deploy_contract.md @@ -10,7 +10,7 @@ You can use this method to deploy your contracts to the sandbox or to a remote n ## Prerequisites -- `aztec-nargo` installed (go to [Sandbox section](../../../reference/developer_references/sandbox_reference/sandbox-reference.md) for installation instructions) +- `aztec-nargo` installed (go to [Sandbox section](../../reference/environment_reference/sandbox-reference.md) for installation instructions) - contract artifacts ready (go to [How to Compile Contract](./how_to_compile_contract.md) for instructions on how to compile contracts) - Aztec Sandbox running (go to [Getting Started](../../getting_started.md) for instructions on how to install and run the sandbox) diff --git a/docs/docs/guides/developer_guides/smart_contracts/index.mdx b/docs/docs/developers/guides/smart_contracts/index.mdx similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/index.mdx rename to docs/docs/developers/guides/smart_contracts/index.mdx diff --git a/docs/docs/guides/developer_guides/smart_contracts/profiling_transactions.md b/docs/docs/developers/guides/smart_contracts/profiling_transactions.md similarity index 96% rename from docs/docs/guides/developer_guides/smart_contracts/profiling_transactions.md rename to docs/docs/developers/guides/smart_contracts/profiling_transactions.md index 66715f452e1..0cd790bd211 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/profiling_transactions.md +++ b/docs/docs/developers/guides/smart_contracts/profiling_transactions.md @@ -14,7 +14,7 @@ In this guide, we will look at how to profile the private execution of a transac ## Prerequisites -- `aztec-nargo` installed (go to [Sandbox section](../../../reference/developer_references/sandbox_reference/sandbox-reference.md) for installation instructions) +- `aztec-nargo` installed (go to [Sandbox section](../../reference/environment_reference/sandbox-reference.md) for installation instructions) - `aztec-wallet` installed (installed as part of the Sandbox) ## Profiling using aztec-wallet diff --git a/docs/docs/guides/developer_guides/smart_contracts/testing.md b/docs/docs/developers/guides/smart_contracts/testing.md similarity index 99% rename from docs/docs/guides/developer_guides/smart_contracts/testing.md rename to docs/docs/developers/guides/smart_contracts/testing.md index 0a5c256c3c8..59b5e4e9cfe 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/testing.md +++ b/docs/docs/developers/guides/smart_contracts/testing.md @@ -215,7 +215,8 @@ You can also use the `assert_public_call_fails` or `assert_private_call_fails` m ### Logging -You can use `aztec.nr`'s oracles as usual for debug logging, as explained [here](../../../reference/developer_references/debugging.md) +You can use `aztec.nr`'s oracles as usual for debug logging, as explained [here](../../reference/debugging/index.md) + :::warning Remember to set the following environment variables to activate debug logging: diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/_category_.json b/docs/docs/developers/guides/smart_contracts/writing_contracts/_category_.json similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/_category_.json rename to docs/docs/developers/guides/smart_contracts/writing_contracts/_category_.json diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/authwit.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/authwit.md similarity index 97% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/authwit.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/authwit.md index dc4af796cfa..cf56fa59876 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/authwit.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/authwit.md @@ -10,13 +10,13 @@ For a guide on using authwit in Aztec.js, [read this](../../js_apps/authwit.md). ## Prerequisite reading -- [Authwit](../../../../aztec/concepts/accounts/authwit.md) +- [Authwit](../../../../aztec/concepts/advanced/authwit.md) ## Introduction Authentication Witness (authwit) is a scheme for authentication actions on Aztec, so users can allow third-parties (eg other contracts) to execute an action on their behalf. Authwits can only authorize actions for contracts that your account is calling, they cannot be used to permit other users to take actions on your behalf. -How it works logically is explained in the [concepts](../../../../aztec/concepts/accounts/authwit.md) but we will do a short recap here. +How it works logically is explained in the [concepts](../../../../aztec/concepts/advanced/authwit.md) but we will do a short recap here. An authentication witness is defined for a specific action, such as allowing a Defi protocol to transfer funds on behalf of the user. An action is here something that could be explained as `A is allowed to perform X operation on behalf of B` and we define it as a hash computed as such: @@ -40,10 +40,7 @@ authentication_witness_action = H( Given the action, the developer can ask the `on_behalf_of` account contract if the action is authenticated or not. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram actor Alice participant AC as Alice Account @@ -68,7 +65,6 @@ sequenceDiagram Defi->>Defi: deposit(Token, 1000); deactivate Defi deactivate AC - ``` :::info @@ -171,7 +167,7 @@ With private functions covered, how can we use this in a public function? Well, Authenticating an action in the public domain is slightly different from the private domain, since we are executing a function on the auth registry contract to add the witness flag. As you might recall, this was to ensure that we don't need to call into the account contract from public, which is a potential DOS vector. -In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [Accounts concepts](../../../../aztec/concepts/accounts/authwit.md#what-about-public). +In the snippet below, this is done as a separate contract call, but can also be done as part of a batch as mentioned in the [Accounts concepts](../../../../aztec/concepts/advanced/authwit.md#what-about-public). #include_code authwit_public_transfer_example /yarn-project/end-to-end/src/e2e_token_contract/transfer_in_public.test.ts typescript @@ -189,10 +185,7 @@ An example of this would be our Uniswap example which performs a cross chain swa Outlining more of the `swap` flow: this simplified diagram shows how it will look for contracts that are not wallets but also need to support authentication witnesses. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram actor A as Alice participant AC as Alice Account @@ -227,7 +220,6 @@ sequenceDiagram CC-->>CC: Emit L2->L1 message deactivate CC; deactivate AC; - ``` :::info **TODO** diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/call_contracts.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/call_contracts.md similarity index 96% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/call_contracts.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/call_contracts.md index 6a47645f5c0..c1573a9abd9 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/call_contracts.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/call_contracts.md @@ -53,7 +53,7 @@ To call a public function from private, you will need to enqueue it like this: #include_code enqueue_public /noir-projects/noir-contracts/contracts/lending_contract/src/main.nr rust -Public functions are always executed after private execution. To learn why, read the [concepts overview](../../../../aztec/concepts_overview.md). +Public functions are always executed after private execution. To learn why, read the [concepts overview](../../../../aztec/index.md). #### Other call types diff --git a/docs/docs/developers/guides/smart_contracts/writing_contracts/call_functions.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/call_functions.md new file mode 100644 index 00000000000..c1573a9abd9 --- /dev/null +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/call_functions.md @@ -0,0 +1,60 @@ +--- +title: Calling Other Contracts +sidebar_position: 4 +tags: [functions, contracts] +--- + +A contract is a collection of persistent state variables and functions which may manipulate these variables. + +Functions and state variables within a contract's scope are said to belong to that contract. A contract can only access and modify its own state. + +If a contract wishes to access or modify another contract's state, it must make a call to an external function of the other contract. For anything to happen on the Aztec network, an external function of a contract needs to be called. + +### Add Contract as a Dependency + +Import the contract that you want to call into your `Nargo.toml` under `dependencies` like this: + +```toml +token = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/noir-contracts/contracts/token_contract" } +``` + +### Import into your contract + +At the top of your contract, import the contract you want to call like this: + +```rust +use token::Token; +``` + +### Call the function + +To call the function, you need to + +- Specify the address of the contract with `Contract::at(contract_address)` +- Call the function name with `.function_name()` +- Pass the parameters into the function call, like `.function_name(param1,param2)` +- Specify the type of call you want to make and pass a mut reference to the context, like `.call(&mut context)` + +#### Private calls + +To call a private function, you can just use `call()` like this: + +#include_code call_function noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr rust + +#### Public -> Public calls + +To call a public function from a public function, it is the same as above. You can just use `call()` like this: + +#include_code public_to_public_call noir-projects/noir-contracts/contracts/lending_contract/src/main.nr rust + +#### Private -> Public calls + +To call a public function from private, you will need to enqueue it like this: + +#include_code enqueue_public /noir-projects/noir-contracts/contracts/lending_contract/src/main.nr rust + +Public functions are always executed after private execution. To learn why, read the [concepts overview](../../../../aztec/index.md). + +#### Other call types + +There are other call types, for example to ensure no state changes are made. You can learn more about them in the [call types glossary](../../../../aztec/glossary/call_types.md). diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md similarity index 91% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md index 6ee1b680d16..27519369e91 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/common_patterns/index.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/common_patterns/index.md @@ -41,7 +41,7 @@ Note - you could also create a note and send it to the user. The problem is ther You can't read public storage in private domain. But nevertheless reading public storage is desirable. There are two ways to achieve the desired effect: -1. For public values that change infrequently, you can use [shared state](../../../../../reference/developer_references/smart_contract_reference/storage/shared_state.md). +1. For public values that change infrequently, you can use [shared state](../../../../reference/smart_contract_reference/storage/shared_state.md). 1. You pass the data as a parameter to your private method and later assert in public that the data is correct. E.g.: @@ -77,7 +77,7 @@ In this situation, try to mark the public function as `internal`. This ensures y ### Moving public data into the private domain -See [partial notes](../../../../../aztec/concepts/storage/partial_notes.md). Partial notes are how public balances are transferred to private [in the NFT contract](../../../../../tutorials/codealong/contract_tutorials/nft_contract.md). +See [partial notes](../../../../../aztec/concepts/advanced/storage/partial_notes.md). Partial notes are how public balances are transferred to private [in the NFT contract](../../../../tutorials/codealong/contract_tutorials/nft_contract.md). ### Discovering my notes @@ -108,7 +108,7 @@ Hence, it's necessary to add a "randomness" field to your note to prevent such a ### L1 -- L2 interactions -Refer to [Token Portal codealong tutorial on bridging tokens between L1 and L2](../../../../../tutorials/codealong/contract_tutorials/token_bridge/index.md) and/or [Uniswap smart contract example that shows how to swap on L1 using funds on L2](../../../../../tutorials/examples/uniswap/index.md). Both examples show how to: +Refer to [Token Portal codealong tutorial on bridging tokens between L1 and L2](../../../../tutorials/codealong/contract_tutorials/token_bridge/0_setup.md) and/or [Uniswap smart contract example that shows how to swap on L1 using funds on L2](../../../../tutorials/codealong/contract_tutorials/uniswap/index.md). Both examples show how to: 1. L1 -> L2 message flow 2. L2 -> L1 message flow @@ -122,7 +122,7 @@ To send a note to someone, they need to have a key which we can encrypt the note There are several patterns here: 1. Give the contract a key and share it amongst all participants. This leaks privacy, as anyone can see all the notes in the contract. -2. `transfer_to_public` funds into the contract - this is used in the [Uniswap smart contract example where a user sends private funds into a Uniswap Portal contract which eventually withdraws to L1 to swap on L1 Uniswap](../../../../../tutorials/examples/uniswap/index.md). This works like Ethereum - to achieve contract composability, you move funds into the public domain. This way the contract doesn't even need keys. +2. `transfer_to_public` funds into the contract - this is used in the [Uniswap smart contract example where a user sends private funds into a Uniswap Portal contract which eventually withdraws to L1 to swap on L1 Uniswap](../../../../tutorials/codealong/contract_tutorials/uniswap/index.md). This works like Ethereum - to achieve contract composability, you move funds into the public domain. This way the contract doesn't even need keys. There are several other designs we are discussing through [in this discourse post](https://discourse.aztec.network/t/how-to-handle-private-escrows-between-two-parties/2440) but they need some changes in the protocol or in our demo contract. If you are interested in this discussion, please participate in the discourse post! diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_emit_event.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_emit_event.md similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_emit_event.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_emit_event.md diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_pop_capsules.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_pop_capsules.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_pop_capsules.md diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_prove_history.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_prove_history.md similarity index 90% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_prove_history.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_prove_history.md index 45d862b7a39..a0e69834bd4 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/how_to_prove_history.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/how_to_prove_history.md @@ -4,11 +4,11 @@ sidebar_position: 4 tags: [contracts] --- -The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as the Archive tree. You can learn more about how it works in the [concepts section](../../../../aztec/concepts/storage/trees/index.md). +The Aztec Protocol uses an append-only Merkle tree to store hashes of the headers of all previous blocks in the chain as its leaves. This is known as the Archive tree. This page is a quick introductory guide to creating historical proofs proofs from the archive tree. -For a reference, go [here](../../../../reference/developer_references/smart_contract_reference/aztec-nr/aztec/history/contract_inclusion.md). +For a reference, go [here](../../../reference/smart_contract_reference/aztec-nr/aztec/history/contract_inclusion.md). ## Inclusion and non-inclusion proofs @@ -81,4 +81,4 @@ You can also prove that a note was not nullified in a specified block by using ` ## Prove contract inclusion, public value inclusion, and use current state in lookups -To see what else you can do with historical proofs, check out the [reference](../../../../reference/developer_references/smart_contract_reference/aztec-nr/aztec/history/contract_inclusion.md) +To see what else you can do with historical proofs, check out the [reference](../../../reference/smart_contract_reference/aztec-nr/aztec/history/contract_inclusion.md) diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/index.mdx b/docs/docs/developers/guides/smart_contracts/writing_contracts/index.mdx similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/index.mdx rename to docs/docs/developers/guides/smart_contracts/writing_contracts/index.mdx diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/initializers.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/initializers.md similarity index 95% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/initializers.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/initializers.md index 25e1a312a43..cf5ae43d209 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/initializers.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/initializers.md @@ -45,4 +45,4 @@ You can set multiple functions as an initializer function simply by annotating e Calling any one of the functions annotated with `#[initializer]` will mark the contract as initialized. -To see an initializer in action, follow the [Counter codealong tutorial](../../../../tutorials/codealong/contract_tutorials/counter_contract.md). +To see an initializer in action, follow the [Counter codealong tutorial](../../../tutorials/codealong/contract_tutorials/counter_contract.md). diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/address_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md similarity index 90% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/address_note.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md index 3c831979e22..956ac9195af 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/address_note.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/address_note.md @@ -40,4 +40,4 @@ In this example, `owner` is the `address` and the `npk_m_hash` of the donor was - [Keys, including nullifier keys and outgoing viewer](../../../../../aztec/concepts/accounts/keys.md) - [How to write a custom note](./custom_note.md) -- [AddressNote reference](../../../../../reference/developer_references/smart_contract_reference/aztec-nr/address-note/address_note.md) +- [AddressNote reference](../../../../reference/smart_contract_reference/aztec-nr/address-note/address_note.md) diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/custom_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md similarity index 97% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/custom_note.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md index 733e1edf7fa..a3cfa178abf 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/custom_note.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/custom_note.md @@ -49,5 +49,5 @@ If you are also planning to be able to access the data with a note in public sta ## Further reading - [What is `#[note]` actually doing? + functions such as serialize() and deserialize()](../../../../../aztec/smart_contracts/functions//attributes.md#custom-notes-note) -- [Macros reference](../../../../../reference/developer_references/smart_contract_reference/macros.md) +- [Macros reference](../../../../reference/smart_contract_reference/macros.md) - [Keys, including npk_m_hash (nullifier public key master)](../../../../../aztec/concepts/accounts/keys.md) diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md similarity index 81% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/index.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md index b92782a21a2..9a35317828d 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/index.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/index.md @@ -4,4 +4,4 @@ sidebar_position: 3 tags: [contracts, notes] --- -Notes are the fundamental data structure in Aztec when working with private state. In this section there are guides about how to work with `AddressNote`, `ValueNote`, and custom notes in Aztec.nr. You can learn more about notes in the [concepts section](../../../../../aztec/concepts/storage/state_model/index.md#private-state). +Notes are the fundamental data structure in Aztec when working with private state. In this section there are guides about how to work with `AddressNote`, `ValueNote`, and custom notes in Aztec.nr. You can learn more about notes in the [concepts section](../../../../../aztec/concepts/storage/state_model.md). diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/value_note.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md similarity index 94% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/value_note.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md index c0511785dba..0a639f59574 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/notes/value_note.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/notes/value_note.md @@ -60,4 +60,4 @@ The `decrement` function works similarly except the `amount` is the number that - [Keys, including nullifier keys and outgoing viewer](../../../../../aztec/concepts/accounts/keys.md) - [How to write a custom note](./custom_note.md) -- [ValueNote reference](../../../../../reference/developer_references/smart_contract_reference/aztec-nr/value-note/value_note.md) +- [ValueNote reference](../../../../reference/smart_contract_reference/aztec-nr/value-note/value_note.md) diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md similarity index 98% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md index 93e00031913..7ea4d5fb30d 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/portals/communicate_with_portal.md @@ -3,7 +3,7 @@ title: Communicating with L1 tags: [contracts, portals] --- -Follow the [token bridge tutorial](../../../../../tutorials/codealong/contract_tutorials/token_bridge/index.md) for hands-on experience writing and deploying a Portal contract. +Follow the [token bridge tutorial](../../../../tutorials/codealong/contract_tutorials/token_bridge/index.md) for hands-on experience writing and deploying a Portal contract. ## Passing data to the rollup @@ -41,7 +41,7 @@ Note that while the `secret` and the `content` are both hashed, they are actuall ### Token bridge example -Computing the `content` must currently be done manually, as we are still adding a number of bytes utilities. A good example exists within the [Token bridge example (codealong tutorial)](../../../../../tutorials/codealong/contract_tutorials/token_bridge/index.md). +Computing the `content` must currently be done manually, as we are still adding a number of bytes utilities. A good example exists within the [Token bridge example (codealong tutorial)](../../../../tutorials/codealong/contract_tutorials/token_bridge/index.md). #include_code claim_public /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/portals/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/portals/index.md similarity index 100% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/portals/index.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/portals/index.md diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/index.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/index.md similarity index 81% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/index.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/storage/index.md index f895fd3e10f..622df964503 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/index.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/index.md @@ -8,7 +8,7 @@ On this page, you will learn how to define storage in your smart contract. To learn more about how storage works in Aztec, read [the concepts](./storage_slots.md). -[See the storage reference](../../../../../reference/developer_references/smart_contract_reference/storage/index.md). +[See the storage reference](../../../../reference/smart_contract_reference/storage/index.md). ```rust #[storage] diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/notes.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/notes.md similarity index 95% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/notes.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/storage/notes.md index 2e8100bb9f8..2093a74e0ce 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/notes.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/notes.md @@ -34,7 +34,7 @@ A couple of things to unpack here: #### Storage "slot" -Storage slots are more literal for public storage, a place where a value is stored. For private storage, a storage slot is logical (more [here](../../../../../aztec/concepts/storage/index.md#private-state-slots---slots-arent-real)). +Storage slots are more literal for public storage, a place where a value is stored. For private storage, a storage slot is logical (more [here](../../../../../aztec/concepts/advanced/storage/storage_slots.md)). #### Silos @@ -83,9 +83,9 @@ To update a value, its previous note hash(es) are nullified. The new note value Some optional background resources on notes can be found here: -- [High level network architecture](../../../../../aztec/concepts_overview.md), specifically the Private Execution Environment +- [High level network architecture](../../../../../aztec/index.md), specifically the Private Execution Environment - [Transaction lifecycle (simple diagram)](../../../../../aztec/concepts/transactions.md#simple-example-of-the-private-transaction-lifecycle) -- [Public and Private state](../../../../../aztec/concepts/storage/state_model/index.md) +- [Public and Private state](../../../../../aztec/concepts/storage/state_model.md) Notes touch several core components of the protocol, but we will focus on a the essentials first. @@ -150,11 +150,10 @@ Notice how the `add` function shows the simplicity of appending a new note to al ### Apply -Try the [NFT tutorial](../../../../../tutorials/codealong/contract_tutorials/nft_contract.md) to see what notes can achieve. In this section you will also find other tutorials using notes in different ways. +Try the [NFT tutorial](../../../../tutorials/codealong/contract_tutorials/nft_contract.md) to see what notes can achieve. In this section you will also find other tutorials using notes in different ways. ### Further reading -- [Storage Trees](../../../../../aztec/concepts/storage/trees/index.md) - [Proof of prior notes](../how_to_prove_history.md) - public/private reading of public/private proof of state (public or private) If you're curious about any of the following related topics, search the documentation for... diff --git a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/storage_slots.md b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/storage_slots.md similarity index 87% rename from docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/storage_slots.md rename to docs/docs/developers/guides/smart_contracts/writing_contracts/storage/storage_slots.md index a4ad001b701..b406a866338 100644 --- a/docs/docs/guides/developer_guides/smart_contracts/writing_contracts/storage/storage_slots.md +++ b/docs/docs/developers/guides/smart_contracts/writing_contracts/storage/storage_slots.md @@ -3,7 +3,7 @@ title: Storage slots tags: [contracts, storage] --- -From the description of storage slots [in the Concepts](../../../../../aztec/concepts/storage/index.md#private-state-slots---slots-arent-real) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. +From the description of storage slots [in the Concepts](../../../../../aztec/concepts/advanced/storage/storage_slots.md) you will get an idea around the logic of storage slots. In this section we will go into more detail and walk through an entire example of how storage slots are computed for private state to improve our storage slot intuition. Recall, that storage slots in the private domain is just a logical construct, and are not "actually" used for lookups, but rather just as a value to constrain against. For the case of the example, we will look at what is inserted into the note hashes tree when adding a note in the Token contract. Specifically, we are looking at the last part of the `transfer` function: @@ -18,10 +18,7 @@ In the end a siloed note hash is computed in the kernel. Some of the syntax below is a little butchered to make it easier to follow variables without the full code. ::: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram alt Call Token->>BalanceMap: Map::new(map_slot); @@ -40,7 +37,6 @@ sequenceDiagram end Context->>Kernel: unique_note_hash = H(nonce, note_hash) Context->>Kernel: siloed_note_hash = H(contract_address, unique_note_hash) - ``` Notice the `siloed_note_hash` at the very end. It's a hash that will be inserted into the note hashes tree. To clarify what this really is, we "unroll" the values to their simplest components. This gives us a better idea around what is actually inserted into the tree. diff --git a/docs/docs/developers/index.md b/docs/docs/developers/index.md new file mode 100644 index 00000000000..8acdf5530b9 --- /dev/null +++ b/docs/docs/developers/index.md @@ -0,0 +1,67 @@ +--- +id: index +sidebar_position: 0 +title: Build +--- + +# Build + +## Get Started + +
+ + +

Getting Started

+
+ + Get started on Aztec by installing the sandbox and playing with it + +
+
+ +## Build applications + +
+ + +

Contract Tutorials

+
+ + Go from zero to hero by following these tutorials in order, starting with a counter contract + +
+ + + +

Full stack app on Aztec

+
+ + Learn how everything works together by building an app in JavaScript that connects to a contract + +
+
+ +## Clone a repo + + + + GitHub Icon + + +

Full stack app on Aztec

+
+ + Learn how everything works together by building an app in JavaScript that connects to a contract + +
+ diff --git a/docs/docs/reference/_category_.json b/docs/docs/developers/reference/considerations/_category_.json similarity index 59% rename from docs/docs/reference/_category_.json rename to docs/docs/developers/reference/considerations/_category_.json index 31e9f9521da..3d16e4d0937 100644 --- a/docs/docs/reference/_category_.json +++ b/docs/docs/developers/reference/considerations/_category_.json @@ -1,5 +1,5 @@ { - "label": "Reference", + "label": "Considerations and Limitations", "position": 4, "collapsible": true, "collapsed": true diff --git a/docs/docs/reference/developer_references/limitations.md b/docs/docs/developers/reference/considerations/limitations.md similarity index 97% rename from docs/docs/reference/developer_references/limitations.md rename to docs/docs/developers/reference/considerations/limitations.md index 60c659119c2..c5c57b7d84d 100644 --- a/docs/docs/reference/developer_references/limitations.md +++ b/docs/docs/developers/reference/considerations/limitations.md @@ -173,11 +173,11 @@ This will be patched in the near future, but unfortunately, app developers might ### New Privacy Standards are required -There are many [patterns](../../guides/privacy_considerations.md) which can leak privacy, even on Aztec. Standards haven't been developed yet, to encourage best practices when designing private smart contracts. +There are many [patterns](../../reference/considerations/privacy_considerations.md) which can leak privacy, even on Aztec. Standards haven't been developed yet, to encourage best practices when designing private smart contracts. #### What are the consequences? -For example, until community standards are developed to reduce the uniqueness of ['Tx Fingerprints'](../../guides/privacy_considerations.md#function-fingerprints-and-tx-fingerprints) app developers might accidentally forfeit some function privacy. +For example, until community standards are developed to reduce the uniqueness of ['Tx Fingerprints'](../../reference/considerations/privacy_considerations.md#function-fingerprints-and-tx-fingerprints) app developers might accidentally forfeit some function privacy. ## Circuit limitations diff --git a/docs/docs/guides/privacy_considerations.md b/docs/docs/developers/reference/considerations/privacy_considerations.md similarity index 100% rename from docs/docs/guides/privacy_considerations.md rename to docs/docs/developers/reference/considerations/privacy_considerations.md diff --git a/docs/docs/developers/reference/debugging/_category_.json b/docs/docs/developers/reference/debugging/_category_.json new file mode 100644 index 00000000000..99db708f09c --- /dev/null +++ b/docs/docs/developers/reference/debugging/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Debugging", + "position": 3, + "collapsible": true, + "collapsed": true +} diff --git a/docs/docs/reference/developer_references/common_errors/aztecnr-errors.md b/docs/docs/developers/reference/debugging/aztecnr-errors.md similarity index 94% rename from docs/docs/reference/developer_references/common_errors/aztecnr-errors.md rename to docs/docs/developers/reference/debugging/aztecnr-errors.md index 2a2b3f3d381..63554f154e5 100644 --- a/docs/docs/reference/developer_references/common_errors/aztecnr-errors.md +++ b/docs/docs/developers/reference/debugging/aztecnr-errors.md @@ -17,7 +17,7 @@ You can learn more about dependencies and their paths [here](../smart_contract_r #### `backend has encountered an error` -This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](../../../guides/developer_guides/local_env/versions-updating.md#updating-aztec-nargo) or uninstalling barretenberg: +This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](../../guides/local_env/versions-updating.md) or uninstalling barretenberg: ```bash nargo backend uninstall acvm-backend-barretenberg @@ -27,7 +27,7 @@ It will then reinstall when you compile. #### `Oracle callback {} not found` & `Oracle callback pedersenHash not found` -This can occasionally happen when there are breaking releases. Make sure that your dependencies in `Nargo.toml` are [updated to the latest release](../../../guides/developer_guides/local_env/versions-updating.md#dependency-versions). +This can occasionally happen when there are breaking releases. Make sure that your dependencies in `Nargo.toml` are [updated to the latest release](../../guides/local_env/versions-updating.md#dependency-versions). #### `error: Failed constraint: 'Public state writes only supported in public functions` diff --git a/docs/docs/reference/developer_references/debugging.md b/docs/docs/developers/reference/debugging/index.md similarity index 98% rename from docs/docs/reference/developer_references/debugging.md rename to docs/docs/developers/reference/debugging/index.md index 1befeeac72b..548a35af9a0 100644 --- a/docs/docs/reference/developer_references/debugging.md +++ b/docs/docs/developers/reference/debugging/index.md @@ -1,6 +1,6 @@ --- title: Debugging -sidebar_position: 4 +sidebar_position: 1 --- ## Logging in Aztec.nr diff --git a/docs/docs/reference/developer_references/common_errors/sandbox-errors.md b/docs/docs/developers/reference/debugging/sandbox-errors.md similarity index 90% rename from docs/docs/reference/developer_references/common_errors/sandbox-errors.md rename to docs/docs/developers/reference/debugging/sandbox-errors.md index 41414eda80d..2dbf490cdca 100644 --- a/docs/docs/reference/developer_references/common_errors/sandbox-errors.md +++ b/docs/docs/developers/reference/debugging/sandbox-errors.md @@ -15,7 +15,7 @@ This section contains a list of errors you may encounter when using Aztec Sandbo ### Kernel Circuits -We have several versions of public and private kernels as explained in [the circuits section in the concepts](../../../aztec/concepts/circuits/index.md). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. +We have several versions of public and private kernels as explained in [the circuits section in the concepts](../../../aztec/concepts/advanced/circuits/index.md). Certain things are only possible in certain versions of the circuits. So always ensure that the right version is being used for proof generation. For example, there is a specific version of the public kernel that only works if the previous kernel iteration was a private kernel. Similarly there is one that only works if the previous kernel was public. Remember that for each function call (i.e. each item in the call stack), there is a new kernel iteration that gets run. @@ -132,17 +132,17 @@ For static calls, no new note hashes or nullifiers can be added to the state. ### Rollup circuit errors -These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](../../../aztec/concepts/circuits/rollup_circuits/index.md) for more information. +These are errors that occur when kernel proofs (transaction proofs) are sent to the rollup circuits to create an L2 block. See [rollup circuits](../../../aztec/concepts/advanced/circuits/rollup_circuits/index.md) for more information. #### 4007 - BASE\_\_INVALID_CHAIN_ID -The L1 chain ID you used in your proof generation (for your private transaction) is different to what the rollup circuits expected. Double check against the global variables passed to noir and the config set in [Aztec's rollup contract (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/Rollup.sol) which are [read in by sequencer GitHub link](https://github.com/AztecProtocol/aztec3-packages/blob/master/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts#L32) and subsequently passed in as inputs to the base rollup. When the sequencer submits the block to the rollup contracts, this is again sanity checked so ensure this is the same everywhere. +The L1 chain ID you used in your proof generation (for your private transaction) is different to what the rollup circuits expected. Double check against the global variables passed to noir and the config set in [Aztec's rollup contract (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/Rollup.sol) which are [read in by sequencer GitHub link](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts#L32) and subsequently passed in as inputs to the base rollup. When the sequencer submits the block to the rollup contracts, this is again sanity checked so ensure this is the same everywhere. #### 4008 - BASE\_\_INVALID_VERSION Same as [section 4007](#4007---base__invalid_chain_id) except the `version` refers to the version of the Aztec L2 instance. -Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](../../../aztec/concepts/storage/trees/indexed_merkle_tree.mdx)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. +Some scary bugs like `4003 - BASE__INVALID_NULLIFIER_SUBTREE` and `4004 - BASE__INVALID_NULLIFIER_RANGE` which are to do malformed nullifier trees (see [Indexed Merkle Trees](../../../aztec/concepts/advanced/storage/indexed_merkle_tree.mdx)) etc may seem unrelated at a glance, but at a closer look may be because of some bug in an application's Aztec.nr code. Same is true for certain instances of `7008 - MEMBERSHIP_CHECK_FAILED`. ### Generic circuit errors @@ -173,7 +173,7 @@ Users may create a proof against a historical state in Aztec. The rollup circuit - using invalid historical L1 to L2 message data tree state - inserting a subtree into the greater tree - we make a smaller merkle tree of all the new note hashes/nullifiers etc that were created in a transaction or in a rollup and add it to the bigger state tree. Before inserting, we do a merkle membership check to ensure that the index to insert at is indeed an empty subtree (otherwise we would be overwriting state). This can happen when `next_available_leaf_index` in the state tree's snapshot is wrong (it is fetched by the sequencer from the archiver). The error message should reveal which tree is causing this issue - - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](../../../aztec/concepts/storage/trees/indexed_merkle_tree.mdx). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. + - nullifier tree related errors - The nullifier tree uses an [Indexed Merkle Tree](../../../aztec/concepts/advanced/storage/indexed_merkle_tree.mdx). It requires additional data from the archiver to know which is the nullifier in the tree that is just below the current nullifier before it can perform batch insertion. If the low nullifier is wrong, or the nullifier is in incorrect range, you may receive this error. --- diff --git a/docs/docs/developers/reference/environment_reference/_category_.json b/docs/docs/developers/reference/environment_reference/_category_.json new file mode 100644 index 00000000000..e51f342c74a --- /dev/null +++ b/docs/docs/developers/reference/environment_reference/_category_.json @@ -0,0 +1,6 @@ +{ + "label": "Developer Environment", + "position": 0, + "collapsible": true, + "collapsed": true +} diff --git a/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md b/docs/docs/developers/reference/environment_reference/cheat_codes.md similarity index 99% rename from docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md rename to docs/docs/developers/reference/environment_reference/cheat_codes.md index 2f96ebf6165..633c386e77b 100644 --- a/docs/docs/reference/developer_references/sandbox_reference/cheat_codes.md +++ b/docs/docs/developers/reference/environment_reference/cheat_codes.md @@ -1,7 +1,7 @@ --- title: Cheat Codes tags: [sandbox] -sidebar_position: 1 +sidebar_position: 4 --- import Disclaimer from "@site/src/components/Disclaimers/\_wip_disclaimer.mdx"; diff --git a/docs/docs/reference/developer_references/cli_reference.md b/docs/docs/developers/reference/environment_reference/cli_reference.md similarity index 99% rename from docs/docs/reference/developer_references/cli_reference.md rename to docs/docs/developers/reference/environment_reference/cli_reference.md index 85d7dae2169..7e922854dc1 100644 --- a/docs/docs/reference/developer_references/cli_reference.md +++ b/docs/docs/developers/reference/environment_reference/cli_reference.md @@ -1,7 +1,7 @@ --- title: CLI Reference tags: [sandbox] -sidebar_position: 1 +sidebar_position: 2 --- :::warning diff --git a/docs/docs/reference/developer_references/cli_wallet_reference.md b/docs/docs/developers/reference/environment_reference/cli_wallet_reference.md similarity index 84% rename from docs/docs/reference/developer_references/cli_wallet_reference.md rename to docs/docs/developers/reference/environment_reference/cli_wallet_reference.md index 2d8fc65a8e6..cc6a0c9658b 100644 --- a/docs/docs/reference/developer_references/cli_wallet_reference.md +++ b/docs/docs/developers/reference/environment_reference/cli_wallet_reference.md @@ -2,7 +2,7 @@ title: CLI Wallet tags: [sandbox, wallet, cli] keywords: [wallet, cli wallet] -sidebar_position: 2 +sidebar_position: 3 --- For development, it may be useful to deploy, transact, or create notes in a non-programmatic way. You can use Aztec's CLI Wallet for thing such as: @@ -10,8 +10,8 @@ For development, it may be useful to deploy, transact, or create notes in a non- - Deploying contracts - Sending transactions - Bridging L1 "Fee Juice" into Aztec -- Pushing arbitrary [notes](../../guides/developer_guides/smart_contracts/writing_contracts/notes/index.md) to your PXE -- Creating [authwits](../../guides/developer_guides/smart_contracts/writing_contracts/authwit.md) +- Pushing arbitrary [notes](../../guides/smart_contracts/writing_contracts/notes/index.md) to your PXE +- Creating [authwits](../../guides/smart_contracts/writing_contracts/authwit.md) - Aliasing info and secrets for further usage - Proving your transactions and profile gate counts @@ -69,9 +69,9 @@ $ aztec-wallet deploy-account -f master_yoda ### Deploy -You can deploy a [compiled contract](../../guides/developer_guides/smart_contracts/how_to_compile_contract.md) to the network. +You can deploy a [compiled contract](../../guides/smart_contracts/how_to_compile_contract.md) to the network. -You probably want to look at flags such as `--init` which allows you to specify the [initializer function](../../guides/developer_guides/smart_contracts/writing_contracts/initializers.md) to call, or `-k` for the [encryption public key](../../aztec/concepts/accounts/keys.md#incoming-viewing-keys) if the contract is expected to have notes being encrypted to it. +You probably want to look at flags such as `--init` which allows you to specify the [initializer function](../../guides/smart_contracts/writing_contracts/initializers.md) to call, or `-k` for the [encryption public key](../../../aztec/concepts/accounts/keys.md#incoming-viewing-keys) if the contract is expected to have notes being encrypted to it. You can pass arguments with the `--arg` flag. @@ -98,7 +98,7 @@ Again, notice how it's not necessary to pass `contracts:jedi_order` as the walle ### Manage authwits -You can use the CLI wallet to quickly generate [Authentication Witnesses](../../guides/developer_guides/smart_contracts/writing_contracts/authwit.md). These allow you to authorize the caller to execute an action on behalf of an account. They get aliased into the `authwits` type. +You can use the CLI wallet to quickly generate [Authentication Witnesses](../../guides/smart_contracts/writing_contracts/authwit.md). These allow you to authorize the caller to execute an action on behalf of an account. They get aliased into the `authwits` type. ### In private @@ -134,7 +134,7 @@ aztec-wallet simulate --from master_yoda --contract-address jedi_order --args "l ### Profile -Simulates a transaction with profiling enabled. This allows you to get the gate count of each private function in the transaction. Read more about profiling [here](../../guides/developer_guides/smart_contracts/profiling_transactions.md). +Simulates a transaction with profiling enabled. This allows you to get the gate count of each private function in the transaction. Read more about profiling [here](../../guides/smart_contracts/profiling_transactions.md). #### Example @@ -167,4 +167,4 @@ aztec-wallet add-note JediMember available_members -a master_yoda -ca jedi_order ``` ## Proving -You can prove a transaction using the aztec-wallet with a running sandbox. Follow the guide [here](../../guides/developer_guides/local_env/sandbox_proving.md#proving-with-aztec-wallet) +You can prove a transaction using the aztec-wallet with a running sandbox. Follow the guide [here](../../guides/local_env/sandbox_proving.md#proving-with-aztec-wallet) diff --git a/docs/docs/reference/developer_references/sandbox_reference/index.md b/docs/docs/developers/reference/environment_reference/index.md similarity index 89% rename from docs/docs/reference/developer_references/sandbox_reference/index.md rename to docs/docs/developers/reference/environment_reference/index.md index b67c867d7b5..669c0329faf 100644 --- a/docs/docs/reference/developer_references/sandbox_reference/index.md +++ b/docs/docs/developers/reference/environment_reference/index.md @@ -1,5 +1,5 @@ --- -title: Sandbox Reference +title: Developer Environment tags: [sandbox] sidebar_position: 0 --- @@ -16,4 +16,4 @@ The current sandbox does not generate or verify proofs, but provides a working e ## Command line tools -Aztec-nargo and aztec CLI are command-line tool allowing you to compile smart contracts. See the [compiling contracts guide](../../../guides/developer_guides/smart_contracts/how_to_compile_contract.md) for more information. +Aztec-nargo and aztec CLI are command-line tool allowing you to compile smart contracts. See the [compiling contracts guide](../../guides/local_env/run_more_than_one_pxe_sandbox.md) for more information. diff --git a/docs/docs/reference/developer_references/sandbox_reference/sandbox-reference.md b/docs/docs/developers/reference/environment_reference/sandbox-reference.md similarity index 97% rename from docs/docs/reference/developer_references/sandbox_reference/sandbox-reference.md rename to docs/docs/developers/reference/environment_reference/sandbox-reference.md index d00ef025751..798d3d52e5e 100644 --- a/docs/docs/reference/developer_references/sandbox_reference/sandbox-reference.md +++ b/docs/docs/developers/reference/environment_reference/sandbox-reference.md @@ -1,12 +1,12 @@ --- title: Sandbox Reference tags: [sandbox] -sidebar_position: 0 +sidebar_position: 1 --- :::tip -For a quick start, follow the [guide](../../../guides/getting_started) to install the sandbox. +For a quick start, follow the [guide](../../getting_started.md) to install the sandbox. ::: @@ -165,7 +165,7 @@ If you wish to run components of the Aztec network stack separately, you can use aztec start --node [nodeOptions] --pxe [pxeOptions] --archiver [archiverOptions] --sequencer [sequencerOptions] --prover [proverOptions] --p2p-bootstrap [p2pOptions] ``` -Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. Eg if you want to run a PXE separately to a node, you can [read this guide](../../../guides/developer_guides/local_env/run_more_than_one_pxe_sandbox.md). +Starting the aztec node alongside a PXE, sequencer or archiver, will attach the components to the node. Eg if you want to run a PXE separately to a node, you can [read this guide](../../guides/local_env/run_more_than_one_pxe_sandbox.md). ## Update the sandbox diff --git a/docs/docs/reference/developer_references/smart_contract_reference/_category_.json b/docs/docs/developers/reference/smart_contract_reference/_category_.json similarity index 82% rename from docs/docs/reference/developer_references/smart_contract_reference/_category_.json rename to docs/docs/developers/reference/smart_contract_reference/_category_.json index 13f5f1ecc0a..968f9bcf0a6 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/_category_.json +++ b/docs/docs/developers/reference/smart_contract_reference/_category_.json @@ -1,6 +1,6 @@ { "label": "Smart Contract Reference", - "position": 3, + "position": 1, "collapsible": true, "collapsed": true } diff --git a/docs/docs/reference/developer_references/smart_contract_reference/contract_artifact.md b/docs/docs/developers/reference/smart_contract_reference/contract_artifact.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/contract_artifact.md rename to docs/docs/developers/reference/smart_contract_reference/contract_artifact.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/dependencies.md b/docs/docs/developers/reference/smart_contract_reference/dependencies.md similarity index 90% rename from docs/docs/reference/developer_references/smart_contract_reference/dependencies.md rename to docs/docs/developers/reference/smart_contract_reference/dependencies.md index 1a2bf74b08c..e54f10f4991 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/dependencies.md +++ b/docs/docs/developers/reference/smart_contract_reference/dependencies.md @@ -20,7 +20,7 @@ This is the core Aztec library that is required for every Aztec.nr smart contrac authwit = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/authwit"} ``` -This allows you to use authentication witnesses in your contract. Read a guide of how to use it [here](../../../guides/developer_guides/smart_contracts/writing_contracts/authwit.md). +This allows you to use authentication witnesses in your contract. Read a guide of how to use it [here](../../guides/smart_contracts/writing_contracts/authwit.md). ## Address note @@ -52,4 +52,4 @@ This library contains types that are used in the Aztec protocol. Find it on [Git value_note = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/value-note" } ``` -This is a library for a note that stores one arbitrary value. You can see an example of how it might be used in the [crowdfunding contract codealong tutorial](../../../tutorials/codealong/contract_tutorials/crowdfunding_contract.md). +This is a library for a note that stores one arbitrary value. You can see an example of how it might be used in the [crowdfunding contract codealong tutorial](../../tutorials/codealong/contract_tutorials/crowdfunding_contract.md). diff --git a/docs/docs/reference/developer_references/smart_contract_reference/globals.md b/docs/docs/developers/reference/smart_contract_reference/globals.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/globals.md rename to docs/docs/developers/reference/smart_contract_reference/globals.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/macros.md b/docs/docs/developers/reference/smart_contract_reference/macros.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/macros.md rename to docs/docs/developers/reference/smart_contract_reference/macros.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/portals/_category_.json b/docs/docs/developers/reference/smart_contract_reference/portals/_category_.json similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/portals/_category_.json rename to docs/docs/developers/reference/smart_contract_reference/portals/_category_.json diff --git a/docs/docs/reference/developer_references/smart_contract_reference/portals/data_structures.md b/docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/portals/data_structures.md rename to docs/docs/developers/reference/smart_contract_reference/portals/data_structures.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/portals/inbox.md b/docs/docs/developers/reference/smart_contract_reference/portals/inbox.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/portals/inbox.md rename to docs/docs/developers/reference/smart_contract_reference/portals/inbox.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/portals/outbox.md b/docs/docs/developers/reference/smart_contract_reference/portals/outbox.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/portals/outbox.md rename to docs/docs/developers/reference/smart_contract_reference/portals/outbox.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/portals/registry.md b/docs/docs/developers/reference/smart_contract_reference/portals/registry.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/portals/registry.md rename to docs/docs/developers/reference/smart_contract_reference/portals/registry.md diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/_category_.json b/docs/docs/developers/reference/smart_contract_reference/storage/_category_.json similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/storage/_category_.json rename to docs/docs/developers/reference/smart_contract_reference/storage/_category_.json diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/index.md b/docs/docs/developers/reference/smart_contract_reference/storage/index.md similarity index 97% rename from docs/docs/reference/developer_references/smart_contract_reference/storage/index.md rename to docs/docs/developers/reference/smart_contract_reference/storage/index.md index d5c3bccd90e..ba028b0930a 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/storage/index.md +++ b/docs/docs/developers/reference/smart_contract_reference/storage/index.md @@ -4,7 +4,7 @@ title: Storage Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its hybrid, privacy-first architecture, the management of this storage is more complex than other blockchains like Ethereum. -To learn how to define a storage struct, read [this guide](../../../../guides/developer_guides/smart_contracts/writing_contracts/storage/index.md). +To learn how to define a storage struct, read [this guide](../../../guides/smart_contracts/writing_contracts/storage/index.md). To learn more about storage slots, read [this explainer in the Concepts section](../../../../aztec/concepts/storage/index.md). You control this storage in Aztec using a struct annotated with `#[storage]`. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. @@ -101,6 +101,6 @@ require(minters[msg.sender], "caller is not minter"); ## Concepts mentioned -- [State Model](../../../../aztec/concepts/storage/state_model/index.md) +- [State Model](../../../../aztec/concepts/storage/state_model.md) - [Public-private execution](../../../../aztec/smart_contracts/functions/public_private_calls.md) - [Function Contexts](../../../../aztec/smart_contracts/functions/context.md) diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md b/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md similarity index 99% rename from docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md rename to docs/docs/developers/reference/smart_contract_reference/storage/private_state.md index ec24ad687b8..62bfa64e793 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/storage/private_state.md +++ b/docs/docs/developers/reference/smart_contract_reference/storage/private_state.md @@ -4,7 +4,7 @@ title: Private State On this page we will look at how to manage private state in Aztec contracts. We will look at how to declare private state, how to read and write to it, and how to use it in your contracts. -For a higher level overview of the state model in Aztec, see the [hybrid state model](../../../../aztec/concepts/storage/state_model/index.md) page. +For a higher level overview of the state model in Aztec, see the [hybrid state model](../../../../aztec/concepts/storage/state_model.md) page. ## Overview diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/public_state.md b/docs/docs/developers/reference/smart_contract_reference/storage/public_state.md similarity index 98% rename from docs/docs/reference/developer_references/smart_contract_reference/storage/public_state.md rename to docs/docs/developers/reference/smart_contract_reference/storage/public_state.md index d49aebd81e2..11848a79f77 100644 --- a/docs/docs/reference/developer_references/smart_contract_reference/storage/public_state.md +++ b/docs/docs/developers/reference/smart_contract_reference/storage/public_state.md @@ -4,7 +4,7 @@ title: Public State On this page we will look at how to manage public state in Aztec contracts. We will look at how to declare public state, how to read and write to it, and how to use it in your contracts. -For a higher level overview of the state model in Aztec, see the [state model](../../../../aztec/concepts/storage/state_model/index.md) concepts page. +For a higher level overview of the state model in Aztec, see the [state model](../../../../aztec/concepts/storage/state_model.md) concepts page. ## `PublicMutable` diff --git a/docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md b/docs/docs/developers/reference/smart_contract_reference/storage/shared_state.md similarity index 100% rename from docs/docs/reference/developer_references/smart_contract_reference/storage/shared_state.md rename to docs/docs/developers/reference/smart_contract_reference/storage/shared_state.md diff --git a/docs/docs/tutorials/_category_.json b/docs/docs/developers/tutorials/_category_.json similarity index 100% rename from docs/docs/tutorials/_category_.json rename to docs/docs/developers/tutorials/_category_.json diff --git a/docs/docs/tutorials/codealong/cli_wallet/_category_.json b/docs/docs/developers/tutorials/codealong/cli_wallet/_category_.json similarity index 100% rename from docs/docs/tutorials/codealong/cli_wallet/_category_.json rename to docs/docs/developers/tutorials/codealong/cli_wallet/_category_.json diff --git a/docs/docs/tutorials/codealong/cli_wallet/faceid_wallet.md b/docs/docs/developers/tutorials/codealong/cli_wallet/faceid_wallet.md similarity index 87% rename from docs/docs/tutorials/codealong/cli_wallet/faceid_wallet.md rename to docs/docs/developers/tutorials/codealong/cli_wallet/faceid_wallet.md index cf2cd0bcde0..d43de43197a 100644 --- a/docs/docs/tutorials/codealong/cli_wallet/faceid_wallet.md +++ b/docs/docs/developers/tutorials/codealong/cli_wallet/faceid_wallet.md @@ -5,7 +5,7 @@ keywords: [wallet, cli wallet, faceid] importance: 3 --- -In this tutorial, we will use Apple Mac's Secure Enclave to store the private key, and use it in Aztec's [CLI Wallet](../../../reference/developer_references/cli_wallet_reference.md). This enables fully private, native, and seedless account abstraction! +In this tutorial, we will use Apple Mac's Secure Enclave to store the private key, and use it in Aztec's [CLI Wallet](../../../reference/environment_reference/cli_wallet_reference.md). This enables fully private, native, and seedless account abstraction! :::warning @@ -15,7 +15,7 @@ Aztec is in active development and this has only been tested on MacOS. Please re ## Prerequisites -For this tutorial, we will need to have the [Sandbox](../../../reference/developer_references/sandbox_reference/index.md) installed. +For this tutorial, we will need to have the [Sandbox](../../../reference/environment_reference/sandbox-reference.md) installed. We also need to install Secretive, a nice open-source package that allows us to store keys on the Secure Enclave. You can head to the [secretive releases page](https://github.com/maxgoedjen/secretive/releases) and get the last release's `zip`, unzip and move to Applications, or use [Homebrew](https://brew.sh/): @@ -45,7 +45,7 @@ Make sure Secretive's "Secret Agent" is running. The Secure Enclave is a protected chip on most recent iPhones and Macs and it's meant to be airgapped. It is not safe to use in production. -Fortunately, Aztec implements [Account Abstraction](../../../aztec/concepts/accounts#what-is-account-abstraction) at the protocol level. You could write logic to allow someone else to recover your account, or use a different key or keys for recovery. +Fortunately, Aztec implements [Account Abstraction](../../../../aztec/concepts/accounts/index.md#what-is-account-abstraction) at the protocol level. You could write logic to allow someone else to recover your account, or use a different key or keys for recovery. ::: @@ -92,7 +92,7 @@ aztec-wallet deploy --from accounts:my-wallet token_contract@Token --args accoun You should get prompted to sign with TouchID or password. Once authorized, you should see `Contract stored in database with aliases last & devtoken` ``` -Check [the reference](../../../reference/developer_references/cli_wallet_reference.md) for the whole set of commands, but these mean: +Check [the reference](../../../reference/environment_reference/cli_wallet_reference.md) for the whole set of commands, but these mean: - --from is the sender: our account `my-wallet`. We use the alias because it's easier than writing the key stored in our Secure Enclave. The wallet resolves the alias and knows where to grab it. - token_contract@Token is a shorthand to look in the `target` folder for our contract `token_contract-Token` @@ -111,7 +111,7 @@ aztec-wallet simulate balance_of_public -ca contracts:devtoken --args accounts:n ### What next -In this tutorial, we created an account with the Aztec's [CLI Wallet](../../../reference/developer_references/cli_wallet_reference.md), using the Apple Mac's Secure Enclave to store the private key. +In this tutorial, we created an account with the Aztec's [CLI Wallet](../../../reference/environment_reference/cli_wallet_reference.md), using the Apple Mac's Secure Enclave to store the private key. You can use a multitude of authentication methods, for example with RSA you could use a passport as a recovery, or even as a signer in a multisig. All of this is based on the account contract. diff --git a/docs/docs/tutorials/codealong/contract_tutorials/_category_.json b/docs/docs/developers/tutorials/codealong/contract_tutorials/_category_.json similarity index 100% rename from docs/docs/tutorials/codealong/contract_tutorials/_category_.json rename to docs/docs/developers/tutorials/codealong/contract_tutorials/_category_.json diff --git a/docs/docs/tutorials/codealong/contract_tutorials/counter_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/counter_contract.md similarity index 95% rename from docs/docs/tutorials/codealong/contract_tutorials/counter_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/counter_contract.md index 0ab8bc479b5..ad07e67aca2 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/counter_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/counter_contract.md @@ -7,9 +7,9 @@ In this guide, we will create our first Aztec.nr smart contract. We will build a ## Prerequisites -- You have followed the [quickstart](../../../guides/getting_started.md) +- You have followed the [quickstart](../../../getting_started.md) - Running Aztec Sandbox -- Installed [Noir LSP](../../../guides/developer_guides/local_env/installing_noir_lsp.md) (optional) +- Installed [Noir LSP](../../../guides/local_env/installing_noir_lsp.md) (optional) ## Set up a project @@ -159,4 +159,4 @@ Follow the private voting contract tutorial on the [next page](./private_voting_ ### Optional: Learn more about concepts mentioned here - - [Functions and annotations like `#[private]`](../../../aztec/smart_contracts/functions/function_transforms.md#private-functions) + - [Functions and annotations like `#[private]`](../../../../aztec/smart_contracts/functions/function_transforms.md#private-functions) diff --git a/docs/docs/tutorials/codealong/contract_tutorials/crowdfunding_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/crowdfunding_contract.md similarity index 95% rename from docs/docs/tutorials/codealong/contract_tutorials/crowdfunding_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/crowdfunding_contract.md index 637572c8493..6ebc0ec0121 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/crowdfunding_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/crowdfunding_contract.md @@ -26,7 +26,7 @@ Along the way you will: ### Install tools -Please ensure that you already have [Installed the Sandbox](../../../guides/getting_started) +Please ensure that you already have [Installed the Sandbox](../../../getting_started) ### Create an Aztec project @@ -196,7 +196,7 @@ Follow the account contract tutorial on the [next page](./write_accounts_contrac ### Optional: Learn more about concepts mentioned here - - [Initializer functions](../../../guides/developer_guides/smart_contracts/writing_contracts/initializers.md) - - [Versions](../../../guides/developer_guides/local_env/versions-updating.md). - - [Authorizing actions](../../../aztec/concepts/accounts/index.md#authorizing-actions) - - [Public logs](../../../guides/developer_guides/smart_contracts/writing_contracts/how_to_emit_event.md#call-emit_public_log) + - [Initializer functions](../../../guides/smart_contracts/writing_contracts/initializers.md) + - [Versions](../../../guides/local_env/versions-updating.md). + - [Authorizing actions](../../../../aztec/concepts/advanced/authwit.md) + - [Public logs](../../../guides/smart_contracts/writing_contracts/how_to_emit_event.md) diff --git a/docs/docs/tutorials/codealong/contract_tutorials/nft_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md similarity index 91% rename from docs/docs/tutorials/codealong/contract_tutorials/nft_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md index cdd551fa0c1..fefa4bf7ed4 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/nft_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/nft_contract.md @@ -87,7 +87,7 @@ These are functions that have transparent logic, will execute in a publicly veri - [`set_minter`](#set_minter) - adds a minter to the `minters` mapping - [`mint`](#mint) - mints an NFT with a specified `token_id` to the recipient - [`transfer_in_public`](#transfer_in_public) - publicly transfer the specified token -- [`finalize_transfer_to_private`](#finalize_transfer_to_private) - finalize the transfer of the NFT from public to private context by completing the [partial note](../../../aztec/concepts/storage/partial_notes.md)(more on this below) +- [`finalize_transfer_to_private`](#finalize_transfer_to_private) - finalize the transfer of the NFT from public to private context by completing the [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md)(more on this below) #### Public `view` functions @@ -103,8 +103,8 @@ These functions are useful for getting contract information for use in other con These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data commitments and nullifiers, so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. -- [`transfer_to_private`](#transfer_to_private) - privately initiates the transfer of an NFT from the public context to the private context by creating a [partial note](../../../aztec/concepts/storage/partial_notes.md) -- [`prepare_private_balance_increase`](#prepare_private_balance_increase) - creates a [partial note](../../../aztec/concepts/storage/partial_notes.md) to transfer an NFT from the public context to the private context. +- [`transfer_to_private`](#transfer_to_private) - privately initiates the transfer of an NFT from the public context to the private context by creating a [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md) +- [`prepare_private_balance_increase`](#prepare_private_balance_increase) - creates a [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md) to transfer an NFT from the public context to the private context. - [`cancel_authwit`](#cancel_authwit) - emits a nullifier to cancel a private authwit - [`transfer_in_private`](#transfer_in_private) - transfers an NFT to another account, privately - [`transfer_to_public`](#transfer_to_public) - transfers a NFT from private to public context @@ -158,7 +158,7 @@ We are also importing types from a `types.nr` file, which imports types from the :::note -Private state in Aztec is all [UTXOs](../../../aztec/concepts/storage/index.md). +Private state in Aztec is all [UTXOs](../../../../aztec/concepts/storage/state_model.md). ::: @@ -172,7 +172,7 @@ Below the dependencies, paste the following Storage struct: ## Custom Notes -The contract storage uses a [custom note](../../../guides/developer_guides/smart_contracts/writing_contracts/notes/custom_note.md) implementation. Custom notes are useful for defining your own data types. You can think of a custom note as a "chunk" of private data, the entire thing is added, updated or nullified (deleted) together. This NFT note is very simple and stores only the owner and the `token_id` and uses `randomness` to hide its contents. +The contract storage uses a [custom note](../../../guides/smart_contracts/writing_contracts/notes/custom_note.md) implementation. Custom notes are useful for defining your own data types. You can think of a custom note as a "chunk" of private data, the entire thing is added, updated or nullified (deleted) together. This NFT note is very simple and stores only the owner and the `token_id` and uses `randomness` to hide its contents. Randomness is required because notes are stored as commitments (hashes) in the note hash tree. Without randomness, the contents of a note may be derived through brute force (e.g. without randomness, if you know my Aztec address, you may be able to figure out which note hash in the tree is mine by hashing my address with many potential `token_id`s). @@ -196,7 +196,7 @@ This function sets the admin and makes them a minter, and sets the name and symb Public functions are declared with the `#[public]` macro above the function name. -As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize notes prepared in a private context ([partial notes flow](../../../aztec/concepts/storage/partial_notes.md)). +As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize notes prepared in a private context ([partial notes flow](../../../../aztec/concepts/advanced/storage/partial_notes.md)). Storage is referenced as `storage.variable`. @@ -255,7 +255,7 @@ Transfers token with `token_id` from public balance of the sender to a private b #### `prepare_private_balance_increase` -This function prepares a [partial note](../../../aztec/concepts/storage/partial_notes.md) to transfer an NFT from the public context to the private context. The caller specifies an `AztecAddress` that will receive the NFT in private storage. +This function prepares a [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md) to transfer an NFT from the public context to the private context. The caller specifies an `AztecAddress` that will receive the NFT in private storage. :::note @@ -275,7 +275,7 @@ Cancels a private authwit by emitting the corresponding nullifier. #### `transfer_in_private` -Transfers an NFT between two addresses in the private context. Uses [authwits](../../../aztec/concepts/accounts/authwit.md) to allow contracts to transfer NFTs on behalf of other accounts. +Transfers an NFT between two addresses in the private context. Uses [authwits](../../../../aztec/concepts/advanced/authwit.md) to allow contracts to transfer NFTs on behalf of other accounts. #include_code transfer_in_private /noir-projects/noir-contracts/contracts/nft_contract/src/main.nr rust @@ -359,7 +359,7 @@ A getter function for checking the private balance of the provided Aztec account ## Compiling -Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../reference/developer_references/sandbox_reference/index.md) for instructions on setting it up. +Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../reference/environment_reference/index.md) for instructions on setting it up. Run the following command in the directory where your `Nargo.toml` file is located: @@ -376,7 +376,7 @@ aztec codegen target -o src/artifacts ### Optional: Dive deeper into this contract and concepts mentioned here - Review [the end to end tests (Github link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/end-to-end/src/e2e_nft.test.ts) for reference. -- [Nullifiers](../../../aztec/concepts/storage/trees/index.md#nullifier-tree) -- [Public / Private function calls](../../../aztec/smart_contracts/functions/public_private_calls.md). -- [Contract Storage](../../../aztec/concepts/storage/index.md) -- [Authwit](../../../aztec/concepts/accounts/authwit.md) +- [Nullifier tree](../../../../aztec/concepts/advanced/storage/indexed_merkle_tree.mdx) +- [Public / Private function calls](../../../../aztec/smart_contracts/functions/public_private_calls.md). +- [Contract Storage](../../../../aztec/concepts/storage/index.md) +- [Authwit](../../../../aztec/concepts/advanced/authwit.md) diff --git a/docs/docs/tutorials/codealong/contract_tutorials/private_voting_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/private_voting_contract.md similarity index 93% rename from docs/docs/tutorials/codealong/contract_tutorials/private_voting_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/private_voting_contract.md index 2c7f0d81f86..499150b03ff 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/private_voting_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/private_voting_contract.md @@ -21,7 +21,7 @@ To keep things simple, we won't create ballots or allow for delegate voting. ## Prerequisites -- You have followed the [quickstart](../../../guides/getting_started) to install `aztec-nargo` and `aztec`. +- You have followed the [quickstart](../../../getting_started.md) to install `aztec-nargo` and `aztec`. - Running Aztec Sandbox ## Set up a project @@ -172,7 +172,7 @@ Follow the crowdfunding contracts tutorial on the [next page](./crowdfunding_con ### Optional: Learn more about concepts mentioned here -- [Unconstrained functions](../../../aztec/smart_contracts/functions/index.md). -- [Oracles](../../../aztec/smart_contracts/oracles/index.md) -- [Nullifier secrets](../../../aztec/concepts/accounts/keys.md#nullifier-secrets). -- [How to deploy a contract to the sandbox](../../../guides/developer_guides/smart_contracts/how_to_deploy_contract.md) +- [Unconstrained functions](../../../../aztec/smart_contracts/functions/attributes.md#unconstrained-functions). +- [Oracles](../../../../aztec/smart_contracts/oracles/index.md) +- [Nullifier secrets](../../../../aztec/concepts/accounts/keys.md#nullifier-keys). +- [How to deploy a contract to the sandbox](../../../guides/smart_contracts/how_to_deploy_contract.md) diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md similarity index 98% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md index 4ec44d065e7..0a4d73b13e0 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/0_setup.md @@ -17,7 +17,7 @@ We recommend going through this setup to fully understand where things live. - [node v18+ (GitHub link)](https://github.com/tj/n) - [docker](https://docs.docker.com/) -- [Aztec sandbox](../../../../../guides/getting_started) - you should have this running before starting the tutorial +- [Aztec sandbox](../../../../../developers/getting_started) - you should have this running before starting the tutorial Start the sandbox diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/1_depositing_to_aztec.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/1_depositing_to_aztec.md similarity index 100% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/1_depositing_to_aztec.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/1_depositing_to_aztec.md diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/2_minting_on_aztec.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/2_minting_on_aztec.md similarity index 100% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/2_minting_on_aztec.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/2_minting_on_aztec.md diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/3_withdrawing_to_l1.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/3_withdrawing_to_l1.md similarity index 100% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/3_withdrawing_to_l1.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/3_withdrawing_to_l1.md diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md similarity index 98% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md index 4020d5f6df8..7af4ab182d6 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/4_typescript_glue_code.md @@ -171,4 +171,4 @@ Follow the tutorial [here](../../js_tutorials/aztecjs-getting-started.md). ### Optional: Learn more about concepts mentioned here -- [Functions under the hood (concepts)](../../../../aztec/smart_contracts/functions/function_transforms.md) +- [Functions under the hood (concepts)](../../../../../aztec/smart_contracts/functions/function_transforms.md) diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_bridge/index.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/index.md similarity index 100% rename from docs/docs/tutorials/codealong/contract_tutorials/token_bridge/index.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_bridge/index.md diff --git a/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_contract.md similarity index 95% rename from docs/docs/tutorials/codealong/contract_tutorials/token_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/token_contract.md index 9c58a4bb160..b3308fa477c 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/token_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/token_contract.md @@ -85,7 +85,7 @@ These are functions that have private logic and will be executed on user devices - [`cancel_authwit`](#cancel_authwit) enables an account to cancel an authorization to spend tokens - [`burn_private`](#burn_private) enables tokens to be burned privately - [`setup_refund`](#setup_refund) allows users using a fee paying contract to receive unspent transaction fees -- [`prepare_private_balance_increase`](#prepare_private_balance_increase) is used to set up a [partial note](../../../aztec/concepts/storage/partial_notes.md) to be completed in public +- [`prepare_private_balance_increase`](#prepare_private_balance_increase) is used to set up a [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md) to be completed in public #### Private `view` functions @@ -101,7 +101,7 @@ Internal functions are functions that can only be called by the contract itself. - [`_increase_public_balance`](#_increase_public_balance) increases the public balance of an account when `transfer_to_public` is called - [`_reduce_total_supply`](#_reduce_total_supply) reduces the total supply of tokens when a token is privately burned -- [`complete_refund`](#complete_refund) used in the fee payment flow. There is more detail on the [partial note](../../../aztec/concepts/storage/partial_notes.md#private-fee-payment-implementation) page. +- [`complete_refund`](#complete_refund) used in the fee payment flow. There is more detail on the [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md#complete_refund) page. - [`_finalize_transfer_to_private_unsafe`](#_finalize_transfer_to_private_unsafe) is the public component for finalizing a transfer from a public balance to private balance. It is considered `unsafe` because `from` is not enforced in this function, but it is in enforced the private function that calls this one (so it's safe). - [`_finalize_mint_to_private_unsafe`](#_finalize_mint_to_private_unsafe) finalizes a private mint. Like the function above, it is considered `unsafe` because `from` is not enforced in this function, but it is in enforced the private function that calls this one (so it's safe). @@ -156,7 +156,7 @@ We are also importing types from a `types.nr` file, which imports types from the :::note -Private state in Aztec is all [UTXOs](../../../aztec/concepts/storage/index.md). +Private state in Aztec is all [UTXOs](../../../../aztec/concepts/storage/index.md). ::: @@ -191,7 +191,7 @@ This function sets the creator of the contract (passed as `msg_sender` from the Public functions are declared with the `#[public]` macro above the function name. -As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize notes prepared in a private context ([partial notes flow](../../../aztec/concepts/storage/partial_notes.md)). +As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to finalize notes prepared in a private context ([partial notes flow](../../../../aztec/concepts/advanced/storage/partial_notes.md)). Storage is referenced as `storage.variable`. @@ -386,13 +386,13 @@ Unconstrained functions are similar to `view` functions in Solidity in that they #### `balance_of_private` -A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE) (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have `ivsk` ([incoming viewing secret key](../../../aztec/concepts/accounts/keys.md#incoming-viewing-keys)) in order to decrypt the notes. +A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE) (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have `ivsk` ([incoming viewing secret key](../../../../aztec/concepts/accounts/keys.md#incoming-viewing-keys)) in order to decrypt the notes. #include_code balance_of_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust ## Compiling -Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../reference/developer_references/sandbox_reference/index.md) for instructions on setting it up. +Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../reference/environment_reference/index.md) for instructions on setting it up. Run the following command in the directory where your `Nargo.toml` file is located: @@ -410,7 +410,7 @@ aztec codegen target -o src/artifacts ### Token Bridge Contract -The [token bridge tutorial](.//token_bridge/index.md) is a great follow up to this one. +The [token bridge tutorial](./token_bridge/index.md) is a great follow up to this one. It builds on the Token contract described here and goes into more detail about Aztec contract composability and Ethereum (L1) and Aztec (L2) cross-chain messaging. @@ -418,7 +418,7 @@ It builds on the Token contract described here and goes into more detail about A - Review [the end to end tests (Github link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/end-to-end/src/e2e_token_contract/) for reference. - [Commitments (Wikipedia link)](https://en.wikipedia.org/wiki/Commitment_scheme) -- [Nullifiers](../../../aztec/concepts/storage/trees/index.md#nullifier-tree) -- [Public / Private function calls](../../../aztec/smart_contracts/functions/public_private_calls.md). -- [Contract Storage](../../../aztec/concepts/storage/index.md) -- [Authwit](../../../aztec/concepts/accounts/authwit.md) +- [Nullifier tree](../../../../aztec/concepts/advanced/storage/indexed_merkle_tree.mdx) +- [Public / Private function calls](../../../../aztec/smart_contracts/functions/public_private_calls.md). +- [Contract Storage](../../../../aztec/concepts/storage/index.md) +- [Authwit](../../../../aztec/concepts/advanced/authwit.md) diff --git a/docs/docs/tutorials/examples/uniswap/_category_.json b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/_category_.json similarity index 100% rename from docs/docs/tutorials/examples/uniswap/_category_.json rename to docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/_category_.json diff --git a/docs/docs/tutorials/examples/uniswap/e2e_tests.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/e2e_tests.md similarity index 100% rename from docs/docs/tutorials/examples/uniswap/e2e_tests.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/e2e_tests.md diff --git a/docs/docs/tutorials/examples/uniswap/index.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/index.md similarity index 87% rename from docs/docs/tutorials/examples/uniswap/index.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/index.md index d31c03b0418..1e3e804f06c 100644 --- a/docs/docs/tutorials/examples/uniswap/index.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/index.md @@ -1,6 +1,6 @@ --- -title: Overview -sidebar_position: 0 +title: Swap on L1 from L2s +sidebar_position: 7 --- import Image from "@theme/IdealImage"; @@ -15,7 +15,7 @@ The flow will be: 2. We create an L2 → L1 message to swap on L1 3. On L1, the user gets their input tokens, consumes the swap message, and executes the swap 4. The user deposits the “output” tokens to the output token portal so it can be deposited into L2 -5. We will assume that token portals and token bridges for the input and output tokens must exist. These are what we built in the [token bridge tutorial](../../codealong/contract_tutorials/token_bridge/index.md). +5. We will assume that token portals and token bridges for the input and output tokens must exist. These are what we built in the [token bridge tutorial](../token_bridge/index.md). The execution of swap on L1 should be designed such that any 3rd party can execute the swap on behalf of the user. This helps maintain user privacy by not requiring links between L1 and L2 activity. @@ -27,5 +27,5 @@ This reference will cover: This diagram describes the private flow. -This code works alongside a token portal that you can learn to build [in this codealong tutorial](../../codealong/contract_tutorials/token_bridge/index.md). +This code works alongside a token portal that you can learn to build [in this codealong tutorial](../token_bridge/index.md). diff --git a/docs/docs/tutorials/examples/uniswap/l1_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l1_contract.md similarity index 94% rename from docs/docs/tutorials/examples/uniswap/l1_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l1_contract.md index c9b16928ed1..eec465e9a20 100644 --- a/docs/docs/tutorials/examples/uniswap/l1_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l1_contract.md @@ -3,7 +3,7 @@ title: L1 contracts (EVM) sidebar_position: 2 --- -This page goes over the code in the L1 contract for Uniswap, which works alongside a [token portal (codealong tutorial)](../../codealong/contract_tutorials/token_bridge/index.md). +This page goes over the code in the L1 contract for Uniswap, which works alongside a [token portal (codealong tutorial)](../token_bridge/index.md). ## Setup diff --git a/docs/docs/tutorials/examples/uniswap/l2_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l2_contract.md similarity index 95% rename from docs/docs/tutorials/examples/uniswap/l2_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l2_contract.md index a3ce0e6de53..597755f9a5e 100644 --- a/docs/docs/tutorials/examples/uniswap/l2_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/uniswap/l2_contract.md @@ -3,7 +3,7 @@ title: L2 Contracts (Aztec) sidebar_position: 1 --- -This page goes over the code in the L2 contract for Uniswap, which works alongside a [token bridge (codealong tutorial)](../../codealong/contract_tutorials/token_bridge/index.md). +This page goes over the code in the L2 contract for Uniswap, which works alongside a [token bridge (codealong tutorial)](../token_bridge/index.md). ## Main.nr @@ -16,11 +16,11 @@ We just need to store the portal address for the token that we want to swap. #include_code swap_public noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr rust -1. We check that `msg.sender()` has appropriate approval to call this on behalf of the sender by constructing an authwit message and checking if `from` has given the approval (read more about authwit [here](../../../aztec/concepts/accounts/authwit.md)). +1. We check that `msg.sender()` has appropriate approval to call this on behalf of the sender by constructing an authwit message and checking if `from` has given the approval (read more about authwit [here](../../../../../aztec/concepts/advanced/authwit.md)). 2. We fetch the underlying aztec token that needs to be swapped. 3. We transfer the user’s funds to the Uniswap contract. Like with Ethereum, the user must have provided approval to the Uniswap contract to do so. The user must provide the nonce they used in the approval for transfer, so that Uniswap can send it to the token contract, to prove it has appropriate approval. 4. Funds are added to the Uniswap contract. -5. Uniswap must exit the input tokens to L1. For this it has to approve the bridge to burn its tokens on its behalf and then actually exit the funds. We call the [`exit_to_l1_public()` method on the token bridge](../../codealong/contract_tutorials/token_bridge/index.md). We use the public flow for exiting since we are operating on public state. +5. Uniswap must exit the input tokens to L1. For this it has to approve the bridge to burn its tokens on its behalf and then actually exit the funds. We call the [`exit_to_l1_public()` method on the token bridge](../token_bridge/3_withdrawing_to_l1.md). We use the public flow for exiting since we are operating on public state. 6. It is not enough for us to simply emit a message to withdraw the funds. We also need to emit a message to display our swap intention. If we do not do this, there is nothing stopping a third party from calling the Uniswap portal with their own parameters and consuming our message. So the Uniswap portal (on L1) needs to know: diff --git a/docs/docs/tutorials/codealong/contract_tutorials/write_accounts_contract.md b/docs/docs/developers/tutorials/codealong/contract_tutorials/write_accounts_contract.md similarity index 90% rename from docs/docs/tutorials/codealong/contract_tutorials/write_accounts_contract.md rename to docs/docs/developers/tutorials/codealong/contract_tutorials/write_accounts_contract.md index 43cd5b5902f..1dcc03e75bf 100644 --- a/docs/docs/tutorials/codealong/contract_tutorials/write_accounts_contract.md +++ b/docs/docs/developers/tutorials/codealong/contract_tutorials/write_accounts_contract.md @@ -17,13 +17,13 @@ You will learn: Writing your own account contract allows you to define the rules by which user transactions are authorized and paid for, as well as how user keys are managed (including key rotation and recovery). In other words, writing an account contract lets you make the most out of account abstraction in the Aztec network. -It is highly recommended that you understand how an [account](../../../aztec/concepts/accounts/index.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../../aztec/concepts/accounts/keys.md). You will also need to know how to write a contract in Noir, as well as some basic [Typescript](https://www.typescriptlang.org/). +It is highly recommended that you understand how an [account](../../../../aztec/concepts/accounts/index.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../../../aztec/concepts/accounts/keys.md). You will also need to know how to write a contract in Noir, as well as some basic [Typescript](https://www.typescriptlang.org/). For this tutorial, we will write an account contract that uses Schnorr signatures for authenticating transaction requests. Every time a transaction payload is passed to this account contract's `entrypoint` function, the account contract requires a valid Schnorr signature, whose signed message matches the transaction payload, and whose signer matches the account contract owner's public key. If the signature fails, the transaction will fail. -For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](../../../aztec/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](../../../aztec/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../../aztec/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. +For the sake of simplicity, we will hardcode the signing public key into the contract, but you could store it [in a private note](../../../../aztec/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](../../../../aztec/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../../../aztec/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. ## Contract @@ -91,7 +91,7 @@ More signing schemes are available in case you want to experiment with other typ Let's try creating a new account backed by our account contract, and interact with a simple token contract to test it works. -To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](../../../aztec/concepts/accounts/keys.md#incoming-viewing-keys), and an instance of our `AccountContract` class: +To create and deploy the account, we will use the `AccountManager` class, which takes an instance of an Private Execution Environment (PXE), a [privacy private key](../../../../aztec/concepts/accounts/keys.md#incoming-viewing-keys), and an instance of our `AccountContract` class: #include_code account-contract-deploy yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript @@ -113,5 +113,5 @@ Lo and behold, we get `Error: Assertion failed: 'verification == true'` when run - [ECDSA signer account contract (GitHub link)](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr) - [Schnorr signer account contract (GitHub link)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/schnorr_account_contract) -- [Account abstraction](../../../aztec/concepts/accounts/index.md#what-is-account-abstraction) -- [Authentication witness](../../../aztec/concepts/accounts/authwit.md) +- [Account abstraction](../../../../aztec/concepts/accounts/index.md#what-is-account-abstraction) +- [Authentication witness](../../../../aztec/concepts/advanced/authwit.md) diff --git a/docs/docs/tutorials/codealong/js_tutorials/_category_.json b/docs/docs/developers/tutorials/codealong/js_tutorials/_category_.json similarity index 100% rename from docs/docs/tutorials/codealong/js_tutorials/_category_.json rename to docs/docs/developers/tutorials/codealong/js_tutorials/_category_.json diff --git a/docs/docs/tutorials/codealong/js_tutorials/aztecjs-getting-started.md b/docs/docs/developers/tutorials/codealong/js_tutorials/aztecjs-getting-started.md similarity index 94% rename from docs/docs/tutorials/codealong/js_tutorials/aztecjs-getting-started.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/aztecjs-getting-started.md index 6dd6b117e5c..2fb60c63e3d 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/aztecjs-getting-started.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/aztecjs-getting-started.md @@ -7,7 +7,7 @@ import Image from "@theme/IdealImage"; In this guide, we will retrieving the Sandbox and deploy a pre-written contract to it using Aztec.js. -This guide assumes you have followed the [quickstart](../../../guides/getting_started.md). +This guide assumes you have followed the [quickstart](../../../../developers/getting_started.md). ## Prerequisites @@ -134,7 +134,7 @@ The sandbox is preloaded with multiple accounts so you don't have to sit and cre #include_code load_accounts /yarn-project/end-to-end/src/composed/e2e_sandbox_example.test.ts typescript -An explanation on accounts on Aztec can be found [here](../../../aztec/concepts/accounts/index.md). +An explanation on accounts on Aztec can be found [here](../../../../aztec/concepts/accounts/index.md). ## Deploy a contract @@ -295,7 +295,7 @@ This function takes: 2. A recipient 3. An amount of tokens to mint -This function starts as private to set up the creation of a [partial note](../../../aztec/concepts/storage/partial_notes.md). The private function calls a public function that checks that the minter is authorized to mint new tokens an increments the public total supply. The recipient of the tokens remains private, but the minter and the amount of tokens minted are public. +This function starts as private to set up the creation of a [partial note](../../../../aztec/concepts/advanced/storage/partial_notes.md). The private function calls a public function that checks that the minter is authorized to mint new tokens an increments the public total supply. The recipient of the tokens remains private, but the minter and the amount of tokens minted are public. Let's now use these functions to mint some tokens to Bob's account using Typescript, add this to `index.ts`: @@ -339,7 +339,7 @@ Our complete output should now be something like: token Bob's balance 10543 +43ms ``` -That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [on the Concepts page here](../../../aztec/concepts/transactions.md). +That's it! We have successfully deployed a token contract to an instance of the Aztec network and mined private state-transitioning transactions. We have also queried the resulting state all via the interfaces provided by the contract. To see exactly what has happened here, you can learn about the transaction flow [on the Concepts page here](../../../../aztec/concepts/transactions.md). ## Next Steps @@ -349,5 +349,5 @@ Follow the [dapp tutorial](./simple_dapp/index.md). ### Optional: Learn more about concepts mentioned here -- [Authentication witness](../../../aztec/concepts/accounts/authwit.md) -- [Functions under the hood](../../../aztec/smart_contracts/functions/function_transforms.md) +- [Authentication witness](../../../../aztec/concepts/advanced/authwit.md) +- [Functions under the hood](../../../../aztec/smart_contracts/functions/function_transforms.md) diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/0_project_setup.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/0_project_setup.md similarity index 100% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/0_project_setup.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/0_project_setup.md diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md similarity index 86% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md index 727b94d079b..fbb5e1bb09d 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/1_pxe_service.md @@ -4,7 +4,7 @@ PXE is a component of the Aztec Protocol that provides a private execution envir As an app developer, the PXE interface provides you with access to the user's accounts and their private state, as well as a connection to the network for accessing public global state. -The [Aztec Sandbox](.././../../../reference/developer_references/sandbox_reference/sandbox-reference.md) runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. +The Aztec Sandbox (reference [here](../../../../reference/environment_reference/sandbox-reference.md)) runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. The Sandbox also includes a set of pre-initialized accounts that you can use from your app. @@ -21,7 +21,7 @@ Let's create our first file `src/index.mjs` with the following contents: #include_code all yarn-project/end-to-end/src/sample-dapp/connect.mjs javascript -Make sure the [Sandbox is running](../../../../guides/getting_started.md) and run the example +Make sure the [Sandbox is running](../../../../getting_started.md) and run the example ```bash node src/index.mjs diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md similarity index 93% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md index 324e3d59d0c..ab5374d707d 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/2_contract_deployment.md @@ -3,7 +3,7 @@ To add contracts to your application, we'll start by creating a new `aztec-nargo` project. We'll then compile the contracts, and write a simple script to deploy them to our Sandbox. :::info -Follow the instructions [here](../../../../guides/getting_started.md) to install `aztec-nargo` if you haven't done so already. +Follow the instructions [here](../../../../getting_started.md) to install `aztec-nargo` if you haven't done so already. ::: ## Initialize Aztec project @@ -73,7 +73,7 @@ Here, we are using the `Contract` class with the compiled artifact to send a new Note that the token's `constructor()` method expects an `owner` address to set as the contract `admin`. We are using the first account from the Sandbox for this. :::info -If you are using the generated typescript classes, you can drop the generic `ContractDeployer` in favor of using the `deploy` method of the generated class, which will automatically load the artifact for you and type-check the constructor arguments. See the [How to deploy a contract](../../../../guides/developer_guides/smart_contracts/how_to_deploy_contract.md) page for more info. +If you are using the generated typescript classes, you can drop the generic `ContractDeployer` in favor of using the `deploy` method of the generated class, which will automatically load the artifact for you and type-check the constructor arguments. See the [How to deploy a contract](../../../../guides/smart_contracts/how_to_deploy_contract.md) page for more info. ::: Run the snippet above as `node src/deploy.mjs`, and you should see the following output, along with a new `addresses.json` file in your project root: diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md similarity index 92% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md index 72583b361af..7b28795ecac 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/3_contract_interaction.md @@ -11,7 +11,7 @@ Let's start by showing our user's private balance for the token across their acc #include_code balance_of_private noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust :::info -Note that this function will only return a valid response for accounts registered in the Private eXecution Environment (PXE), since it requires access to the [user's private state](../../../../aztec/concepts/wallets/index.md#private-state). In other words, you cannot query the private balance of another user for the token contract. +Note that this function will only return a valid response for accounts registered in the Private eXecution Environment (PXE), since it requires access to the [user's private state](../../../../../aztec/concepts/wallets/index.md#private-state). In other words, you cannot query the private balance of another user for the token contract. ::: To do this, let's first initialize a new `Contract` instance using `aztec.js` that represents our deployed token contracts. Create a new `src/contracts.mjs` file with the imports for our artifacts and other dependencies: @@ -99,12 +99,12 @@ At the time of this writing, there are no events emitted when new private notes ## Working with public state -While [private and public state](../../../../aztec/concepts/storage/state_model/index.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: +While [private and public state](../../../../../aztec/concepts/storage/index.md) are fundamentally different, the API for working with private and public functions and state from `aztec.js` is equivalent. To query the balance in public tokens for our user accounts, we can just call the `balance_of_public` view function in the contract: #include_code showPublicBalances yarn-project/end-to-end/src/sample-dapp/index.mjs javascript :::info -Since this we are working with public balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](../../../../aztec/concepts/accounts/keys.md#encryption-keys). +Since this we are working with public balances, we can now query the balance for any address, not just those registered in our local PXE. We can also send funds to addresses for which we don't know their [public encryption key](../../../../../aztec/concepts/accounts/keys.md#keys-generation). ::: Here, since the token contract does not mint any initial funds upon deployment, the balances for all of our user's accounts will be zero. diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md similarity index 94% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md index d162345d448..1c0b037fd9d 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/4_testing.md @@ -14,7 +14,7 @@ Start by installing our test runner, in this case jest: yarn add -D jest ``` -We'll need to [install and run the Sandbox](../../../../guides/getting_started.md). +We'll need to [install and run the Sandbox](../../../../getting_started.md). ## Test setup @@ -71,4 +71,4 @@ yarn node --experimental-vm-modules $(yarn bin jest) --testRegex '.*\.test\.mjs$ Have you written a contract from scratch? If not, follow a tutorial for [writing contracts with Noir](../../contract_tutorials/counter_contract.md) -Or read about the [fundamental concepts behind Aztec Network](../../../../aztec/concepts_overview.md) and dive deeper into how things work. +Or read about the [fundamental concepts behind Aztec Network](../../../../../aztec) and dive deeper into how things work. diff --git a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/index.md b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/index.md similarity index 92% rename from docs/docs/tutorials/codealong/js_tutorials/simple_dapp/index.md rename to docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/index.md index 5457d22e4c5..8e8d532689d 100644 --- a/docs/docs/tutorials/codealong/js_tutorials/simple_dapp/index.md +++ b/docs/docs/developers/tutorials/codealong/js_tutorials/simple_dapp/index.md @@ -4,7 +4,7 @@ title: Node.js app that interacts with contracts In this tutorial we'll go through the steps for building a simple application that interacts with the Aztec Sandbox. We'll be building a console application using Javascript and NodeJS, but you may reuse the same concepts here for a web-based app. All Aztec libraries are written in Typescript and fully typed, so you can use Typescript instead of Javascript to make the most out of its type checker. -This tutorial will focus on environment setup, including creating accounts and deployments, as well as interacting with your contracts. It will not cover [how to write contracts in Noir](../../../../aztec/smart_contracts_overview.md). +This tutorial will focus on environment setup, including creating accounts and deployments, as well as interacting with your contracts. It will not cover [how to write contracts in Noir](../../../../../aztec/smart_contracts_overview.md). The full code for this tutorial is [available on the `aztec-packages` repository](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/end-to-end/src/sample-dapp). @@ -12,7 +12,7 @@ The full code for this tutorial is [available on the `aztec-packages` repository - Linux or OSX environment - [NodeJS](https://nodejs.org/) 18 or higher -- [Aztec Sandbox](../../../guides/getting_started) +- [Aztec Sandbox](../../../../getting_started.md) ## Prerequisites diff --git a/docs/docs/guides/developer_guides/running_nodes/running_provers.md b/docs/docs/guides/developer_guides/running_nodes/running_provers.md deleted file mode 100644 index 65c66279486..00000000000 --- a/docs/docs/guides/developer_guides/running_nodes/running_provers.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -draft: true ---- - -# Running Prover Nodes - -TODO(https://github.com/AztecProtocol/aztec-packages/issues/9190) -_Details about how to configure a prover node and hardware requirements are to be determined. This guide will be updated once the information becomes available._ - -For the current state of design please see the RFC at https://forum.aztec.network/t/request-for-comments-aztecs-block-production-system/6155. - -## Overview of Prover Nodes - -Prover nodes play a critical role in the Aztec network by generating zero-knowledge proofs (ZKPs) that finalize blocks on the Proven Chain. - -### Role of Prover Nodes - -- **Proof Generation**: Provers generate zero-knowledge proofs for entire epochs, ensuring the validity of transactions and state transitions. These are verified by the solidity rollup smart contract on Ethereum. -- **Finalizing Blocks**: Proofs are submitted to the rollup contract on Layer 1 (L1) to finalize blocks on the Proven Chain. - -### Prover Bond - -- **Bond Requirement**: Provers must post a bond denominated in TST tokens (bond details subject to change). -- **Commitment**: The bond serves as a commitment to produce valid proofs within a specified time frame. -- **Slashing**: Failure to deliver proofs results in bond slashing, incentivizing timely and accurate proof generation. - -### Consensus Participation - -- **Collaboration with Validators**: Provers work alongside validators to secure the network and advance the Proven Chain. -- **Proof Submission**: Provers submit proofs to the rollup contract, which are then verified and used to finalize blocks. -- **Incentives**: Provers are rewarded for timely and accurate proof generation, promoting network health. diff --git a/docs/docs/guides/developer_guides/running_nodes/running_validators.md b/docs/docs/guides/developer_guides/running_nodes/running_validators.md deleted file mode 100644 index 45588045341..00000000000 --- a/docs/docs/guides/developer_guides/running_nodes/running_validators.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -draft: true ---- - -# Aztec Validator Node Guide - -## Introduction - -This guide provides step-by-step instructions on how to set up an Aztec Layer 2 validator node. Running a node allows you to participate in the Aztec network as a validator (also known as a sequencer or proposer), contributing to the network's security and decentralization. - -The use of Docker means that the environment is set up in a way that works in a variety of environments. For complex deployments with load balancing (for validator redundancy to maximize liveness) there are helm charts available for use with kubernetes (with the same images). - -## Table of Contents - -1. [Prerequisites](#prerequisites) -2. [Port Forwarding](#port-forwarding) -3. [Setting Up on Ubuntu 24](#setting-up-on-ubuntu-24) -4. [Setting Up on Other Operating Systems](#setting-up-on-other-operating-systems) -5. [Configuring Deployment](#configuring-deployment) -6. [Troubleshooting](#troubleshooting) -7. [Background Knowledge](#background-knowledge) - ---- - -## Prerequisites - -- **Operating System**: One of the following - - Ubuntu 24.04 LTS - - macOS - - Windows -- **Knowledge**: Basic familiarity with running commands on a command-line interface. -- **Hardware Requirements**: - -``` - 🖥️ Minimum Recommended -|---------|---------------|----------------| -| CPU | 16 cores | 32 cores | -| Network | 32 mb/s | 128 mb/s | -| Storage | 3 TB | 5 TB | -| RAM | 32 GB | 64 GB | -``` - -## Port Forwarding - -### Understanding Port Forwarding - -Port forwarding allows external devices to access services on a private network by mapping an external port to an internal IP address and port. It's crucial for your Aztec node to communicate with other nodes in the network and form a decentralized peer network. You will need one open UDP port per validator instance you wish to run (even if they are on the same computer). - -- **Reference Guide**: [How to Set Up Port Forwarding on a Router](https://www.noip.com/support/knowledgebase/general-port-forwarding-guide/) -- If using a cloud provider, use security groups (for AWS) or a similar capability to configure open UDP ports on your server. - -### When Port Forwarding Is Not Possible - -Port forwarding may not be possible under certain conditions: - -- **ISP Restrictions**: Some Internet Service Providers (ISPs) block port forwarding. -- **Network Limitations**: If you're on a public or corporate network without router access. - -#### Workarounds - -For example, a restrictive setup like hotel Wi-Fi would require the use of a VPN, using `socat` into a port-forwarded computer, or just using a cloud instance directly with instructions above. Note: It may be possible to use a P2P relay service that works with the DiscV5 protocol, but it is currently untested. - -## Setting Up on Ubuntu 24 - -**Note**: The scripts mentioned here do not currently work on ARM architectures. Support for ARM will be added in the future. - -### Updating the System - -Open your terminal and update your package list: - -```bash -sudo apt update -``` - -### Installing Docker - -Install Docker to manage containerized applications: - -```bash -sudo apt install docker.io -``` - -### Starting Docker Service - -Start and enable the Docker service: - -```bash -sudo systemctl start docker -sudo systemctl enable docker -``` - -### Setting Up Docker User Group - -Add your user to the Docker group to run Docker commands without `sudo`: - -```bash -sudo groupadd docker -sudo usermod -aG docker $USER -newgrp docker -``` - -### Cloning the Aztec Packages Repository - -Clone the Aztec Protocol packages from GitHub: - -```bash -git clone https://github.com/AztecProtocol/aztec-packages -``` - -### Copying the Deploy Script - -Navigate to the directory where you cloned the repository, and copy the deploy script to your home directory: - -```bash -cd aztec-packages -cp spartan/oitavos/deploy-oitavos-team.sh ~/deploy.sh -``` - -**Note**: The script `deploy-oitavos-team.sh` is a temporary name and will be updated in future releases. This script deploys a validator node. - -### Exporting Environment Variables - -Export the following environment variables that will remain constant for your deployment: - -```bash -export AZTEC_IMAGE=your_aztec_image -export ETHEREUM_HOST=your_ethereum_host -export BOOT_NODE_URL=your_boot_node_url -export PUBLIC_IP=your_public_ip -``` - -- **AZTEC_IMAGE**: The Docker image for the Aztec node. -- **ETHEREUM_HOST**: The Ethereum host node your validator will connect to. -- **BOOT_NODE_URL**: The URL of the boot node for peer discovery. -- **PUBLIC_IP**: The public IP address of your machine. - -Replace the placeholders with your actual values. - -### Deploying the Validator Node - -Whenever you want to launch a validator instance, you need to run a container with unique ports. Since the deploy script reads and writes from the current working directory, create a separate directory for each validator. - -For example, to launch the first validator: - -```bash -mkdir val1 -cd val1 -VALIDATOR_PRIVATE_KEY=your_validator_private_key \ -VALIDATOR_ADDRESS=your_validator_address \ -NODE_PORT=8080 \ -P2P_TCP_PORT=40400 \ -P2P_UDP_PORT=40500 \ -~/deploy.sh -``` - -- **VALIDATOR_PRIVATE_KEY**: Your validator's private key. -- **VALIDATOR_ADDRESS**: Your validator's Ethereum address. -- **NODE_PORT**: The HTTP port for your node (use a unique port for each validator). -- **P2P_TCP_PORT** and **P2P_UDP_PORT**: Must be port-forward as detailed above! The TCP and UDP ports for peer-to-peer communication (use unique ports). - -Replace the placeholders with your actual values. - -To deploy additional validators, use different directories and ports: - -```bash -# Ensure the same environment variables exported earlier are set -mkdir val2 -cd val2 -VALIDATOR_PRIVATE_KEY=another_validator_private_key \ -VALIDATOR_ADDRESS=another_validator_address \ -NODE_PORT=8081 \ -P2P_TCP_PORT=40401 \ -P2P_UDP_PORT=40501 \ -~/deploy.sh -``` - -Ensure that each validator instance uses unique ports to avoid conflicts. - -## Setting Up on Other Operating Systems - -### macOS - -**Installing Docker Desktop**: - -- Download and install [Docker Desktop for Mac](https://www.docker.com/products/docker-desktop). - -**Installing Homebrew** (if not already installed): - -```bash -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -``` - -** (Optional) Installing Kind and Helm**: - -```bash -brew install kind -brew install helm -``` - -** (Optional) Setting Up Kubernetes**: - -- Docker Desktop includes Kubernetes; enable it in the Docker settings. - -### Windows - -**Installing Docker Desktop**: - -- Download and install [Docker Desktop for Windows](https://www.docker.com/products/docker-desktop). - -**Enabling WSL 2 Backend**: - -- Follow the instructions to enable the Windows Subsystem for Linux (WSL 2). - -**Installing Chocolatey** (Windows Package Manager): - -- Run the following in PowerShell as Administrator: - - ```powershell - Set-ExecutionPolicy Bypass -Scope Process -Force; ` - [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; ` - iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - ``` - -** (Optional) Installing Kind and Helm**: - -```powershell -choco install kind -choco install kubernetes-helm -``` - -## Configuring Deployment - -Before deploying your validator node, ensure you have a funded Ethereum address on the network you are joining. For test networks, you may need to use a faucet or contact network maintainers for test ETH. - -### Preparing Your Validator Credentials - -- **Validator Private Key**: The private key corresponding to your validator's Ethereum address. -- **Validator Address**: Your validator's Ethereum address. - -### Setting Up Environment Variables - -Export the necessary environment variables: - -```bash -export AZTEC_IMAGE=your_aztec_image -export ETHEREUM_HOST=your_ethereum_host -export BOOT_NODE_URL=your_boot_node_url -export PUBLIC_IP=your_public_ip -``` - -Ensure these variables are set in your shell session before deploying the validator. - -### Deploying the Validator Node - -Follow the steps outlined in the [Deploying the Validator Node](#deploying-the-validator-node) section under **Setting Up on Ubuntu 24** to launch your validator instance. - -For multiple validators, ensure that each instance uses unique ports and directories. - -### Deploying the Cluster (Advanced) - -If you are deploying a cluster of validator nodes using Kubernetes, you can use the provided deployment script: - -```bash -./deploy-oitavos-spartan.sh aztecprotocol/aztec:your_stable_image -``` - -This script will add external load balancing services to the `oitavos` namespace. - -After running the script: - -1. Update the values in `oitavos-spartan.yaml` with the new service addresses. -2. Cancel the deployment and rerun it to apply the updated values. -3. In the `oitavos` namespace, restart the prover node pod to apply the new configuration. - -**Note**: In future releases, the pods may be able to dynamically grab the addresses without manual intervention. -**Note**: Name subject to change. - -## Troubleshooting - -- Check logs for error messages. -- Verify network connectivity, e.g., running isolated commands to ensure that your UDP ports are open. -- Open issues on [GitHub](https://github.com/AztecProtocol/aztec-packages/issues) for suspected bugs or gaps in documentation. - -## Background Knowledge - -This is a brief summary to understand what the validator is doing at a high level. For the current state of design, please see the [RFC](https://forum.aztec.network/t/request-for-comments-aztecs-block-production-system/6155). - -Validators are selected through a committee selection process: - -- **Epoch Initialization**: - - - At the start of each epoch, the rollup contract computes a random seed using `block.prevrandao`. - - The seed is used to select a committee of validators using the Swap-or-Not algorithm. - - The committee size is fixed for the duration of the epoch. - -- **Proposer Selection**: - - - Each validator in the committee is assigned proposer duties for specific slots within the epoch. - - Proposers know in advance when they will be required to propose a block. - -- **Validator Registration**: - - - The rollup contract maintains the active set of validators. - - Updates to the validator set occur at the beginning of new epochs. - - Registration includes staking a minimum threshold of collateral (amount to be determined). - -- **Interaction with the Contract**: - - Validators interact with the rollup contract to fulfill their duties. - - Proposers submit block proposals and proofs to the contract. diff --git a/docs/docs/guides/index.md b/docs/docs/guides/index.md deleted file mode 100644 index 05eb85fea9b..00000000000 --- a/docs/docs/guides/index.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -id: index -sidebar_position: 0 -title: Guides and Tutorials ---- - -# Guides and Tutorials - -In this section you will find: - -- A list of tutorials in order of increasing complexity, allowing you to write contracts and build applications on Aztec -- How-to guides for accomplishing quick, specific goals - -## Getting Started - -
- - -

Getting Started

-
- - Get started on Aztec by installing the sandbox and playing with it - -
-
- -## Building applications - -
- - -

Contract Tutorials

-
- - Go from zero to hero by following these tutorials in order, starting with a counter contract - -
- - - -

Full stack app on Aztec

-
- - Learn how everything works together by building an app in JavaScript that connects to a contract - -
-
diff --git a/docs/docs/index.mdx b/docs/docs/index.mdx index c4a07c69652..79431c7fa54 100644 --- a/docs/docs/index.mdx +++ b/docs/docs/index.mdx @@ -22,12 +22,12 @@ On Ethereum today, everything is publicly visible, by everyone. In the real worl To make this possible, Aztec is *not EVM compatible* and is extending the Ethereum ecosystem by creating a new alt-VM! -To learn more about how Aztec achieves these things, check out the [Aztec concepts overview](/aztec/concepts_overview). +To learn more about how Aztec achieves these things, check out the [Aztec concepts overview](/aztec). ## Start coding
- +

Developer Getting Started Guide

@@ -40,7 +40,7 @@ To learn more about how Aztec achieves these things, check out the [Aztec concep ## Learn how Aztec works
- +

Aztec Overview

diff --git a/docs/docs/migration_notes.md b/docs/docs/migration_notes.md index 84912b63530..2a52292eb8d 100644 --- a/docs/docs/migration_notes.md +++ b/docs/docs/migration_notes.md @@ -6,6 +6,27 @@ keywords: [sandbox, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +### TBD + +### [Aztec.nr] Introduction of `WithHash` +`WithHash` is a struct that allows for efficient reading of value `T` from public storage in private. +This is achieved by storing the value with its hash, then obtaining the values via an oracle and verifying them against the hash. +This results in in a fewer tree inclusion proofs for values `T` that are packed into more than a single field. + +`WithHash` is leveraged by state variables like `PublicImmutable`. +This is a breaking change because now we require values stored in `PublicImmutable` and `SharedMutable` to implement the `Eq` trait. + +To implement the `Eq` trait you can use the `#[derive(Eq)]` macro: + +```diff ++ use std::meta::derive; + ++ #[derive(Eq)] +pub struct YourType { + ... +} +``` + ## 0.73.0 ### [Token, FPC] Moving fee-related complexity from the Token to the FPC diff --git a/docs/docs/protocol-specs/calls/public-private-messaging.md b/docs/docs/protocol-specs/calls/public-private-messaging.md index a1121fbad46..3dc4ab83e5e 100644 --- a/docs/docs/protocol-specs/calls/public-private-messaging.md +++ b/docs/docs/protocol-specs/calls/public-private-messaging.md @@ -19,10 +19,7 @@ Since private functions execute first, they cannot 'wait' on the results of thei By way of example, suppose a function makes a call to a public function, and then to a private function. The public function will not be executed immediately, but will instead be enqueued for the sequencer to execute later. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A[Private Function 1] --> |1st call| B(Public Function 1) A --> |2nd call| C[Private Function 2] @@ -30,15 +27,11 @@ graph LR A --> |3rd call| D(Public Function 2) A --> |4th call| E[Private Function 3] E --> |return values| A - ``` The order of execution will actually be: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A[Private Function 1] --> C[Private Function 2] C --> |return values| A @@ -46,18 +39,13 @@ graph LR E --> |return values| A A -----> |Enqueued| B(Public Function 1) A -----> |Enqueued| D(Public Function 2) - ``` And the order of proving will actually be: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid flowchart LR A[Private Function 1] --> C[Private Function 2] --> E[Private Function 3] ----> B(Public Function 1) --> D(Public Function 2) - ``` ## Private to Public Messaging diff --git a/docs/docs/protocol-specs/circuits/high-level-topology.md b/docs/docs/protocol-specs/circuits/high-level-topology.md index caca2bee49b..43f00cb05ea 100644 --- a/docs/docs/protocol-specs/circuits/high-level-topology.md +++ b/docs/docs/protocol-specs/circuits/high-level-topology.md @@ -15,10 +15,7 @@ A note for Aztec protocol developers: In this protocol spec, the order in which -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid flowchart LR f0([f0]) --> f1([f1]) f0 --> f2([f2]) @@ -30,15 +27,11 @@ flowchart LR f3 --> f4([f4]) f3 -.-> F4 f3 --> f5([f5]) - ``` This transaction contains 6 private functions (f0 to f5) and 5 public functions (F0 to F4), with `f0` being the entrypoint. The entire transaction is processed as follows: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid flowchart TB subgraph Transaction A subgraph Private Functions @@ -133,7 +126,6 @@ flowchart TB MR1 --> MR2 MR2 --> ROOT MR3 --> ROOT - ``` A few things to note: diff --git a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx index 2258bd68251..4d414ea9909 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx +++ b/docs/docs/protocol-specs/circuits/private-kernel-initial.mdx @@ -296,10 +296,7 @@ Key:
-```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction LR class ParentClass { @@ -323,7 +320,6 @@ class D { ParentClass *-- ChildClass: Composition. A .. B: Perform a consistency check on values in these classes. C ..> D: Copy the data from the inputs A to the outputs B\n(possibly with some modification along the way). - ```
@@ -339,10 +335,7 @@ The diagram:
-```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -701,7 +694,7 @@ class PublicInputs { } ConstantData --* PublicInputs : constant_data TransientAccumulatedData --* PublicInputs: transient_accumulated_data - + ```
diff --git a/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx b/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx index 10546522b34..78d97022a67 100644 --- a/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx +++ b/docs/docs/protocol-specs/circuits/private-kernel-inner.mdx @@ -130,10 +130,7 @@ NOTE TO ANYONE EDITING THIS DIAGRAM: To save repeating yourself, you only need to edit the END of this diagram (demarcated clearly, further down the page - you'll see it). COPY-PASTE the beginning of this diagram (up to the demarcation) from ../private-kernel-initial. --> -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -552,6 +549,7 @@ PrivateKernelPublicInputs ..> KERNEL_PROOF_VERIFICATION KernelVerificationKey ..> KERNEL_VK_EXISTENCE_CHECK KernelVKMembershipWitness ..> KERNEL_VK_EXISTENCE_CHECK + ```
diff --git a/docs/docs/protocol-specs/cryptography/hashing/hashing.md b/docs/docs/protocol-specs/cryptography/hashing/hashing.md index 6f83f0b8f98..bb093888eb6 100644 --- a/docs/docs/protocol-specs/cryptography/hashing/hashing.md +++ b/docs/docs/protocol-specs/cryptography/hashing/hashing.md @@ -14,7 +14,7 @@ To minimize the potential for collisions between distinct hashing contexts, all In the case of using Poseidon2 for hashing (which is the case for most hashing in the Aztec protocol), the string is converted from a big-endian byte representation into a `Field` element, and passed as a first argument into the hash. In the case of using non-algebraic hash functions (such as sha256), the string is converted from a big-endian byte representation into bits, and passed as the first bits into the hash. These details are conveyed more clearly as pseudocode in the relevant sections of the spec. -For some hashes there is further domain-separation. For example, [Merkle tree hashing](../../../aztec/concepts/storage/trees/index.md#layers) of the tree. +For some hashes there is further domain-separation. For example, [Merkle tree hashing](../merkle-trees.md#hashing) of the tree. ### Pseudo-randomness diff --git a/docs/docs/protocol-specs/decentralization/block-production.md b/docs/docs/protocol-specs/decentralization/block-production.md index 0306f1fd119..a344e68efff 100644 --- a/docs/docs/protocol-specs/decentralization/block-production.md +++ b/docs/docs/protocol-specs/decentralization/block-production.md @@ -1,4 +1,8 @@ -# Aztec Block Production +--- +title: Block Production +draft: true +--- + :::info This document aims to be the latest source of truth for the Fernet sequencer selection protocol, and reflect the decision to implement the [Sidecar](https://forum.aztec.network/t/proposal-prover-coordination-sidecar/2428) proving coordination protocol. Notably, this is written within the context of the first instance or deployment of Aztec. The definitions and protocol may evolve over time with each version. @@ -88,12 +92,7 @@ What is Aztec's economic security needs? Please clarify. Currently, Provers don't need to register but must commit a bond during the `prover commitment phase` articulated below. This ensures economic guarantees for timely proof generation, and therefore short-term liveness. If the prover is unable or unwilling to produce a proof for which they committed to in the allotted time their bond will be slashed. -Future updates may introduce a registration process for Provers, possibly leading to a smaller, more consistent group, but this is currently not suggested to be required. - -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone @@ -101,9 +100,8 @@ participant Contract as Aztec L1 Contract participant Network as Aztec Network Anyone ->> Contract: register as a sequencer -Anyone --> Anyone: Wait 7 days +Anyone --> Anyone: Wait epoch Anyone ->> Network: eligible as a sequencer - ``` ## Block production @@ -130,10 +128,7 @@ Every staked sequencers participate in the following phases, comprising an Aztec - For data layers that is not on the host, the host must have learned of the publication from the **Reveal** before the **Finalization** can begin. 6. **Backup:** Should no prover commitment be put down, or should the block not get finalized, then an additional phase is opened where anyone can submit a block with its proof, in a based-rollup mode. In the backup phase, the first rollup verified will become canonical. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Contract as Aztec L1 Contract @@ -156,7 +151,6 @@ loop Happy Path Block Production Contract --> Contract: validates proofs and state transition Note right of Contract: "block confirmed!" end - ``` ### Constraining Randao @@ -185,10 +179,7 @@ When a sequencer move to `exiting`, they might have to await for an additional d **Lasse Comment**: I'm unsure what you mean by "active" here. Is active that you are able to produce blocks? Is so, active seems fine. Also, not clear to me if `exiting` means that they be unable to propose blocks? If they are voting in them, sure put a delay in there, but otherwise I don't see why they should be unable to leave (when we don't have consensus for block production). ::: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone as Sequencer @@ -199,8 +190,6 @@ Anyone ->> Contract: exit() from being a sequencer Note left of Contract: Sequencer no longer eligible for Fernet elections Anyone --> Anyone: Wait 7-21 days Anyone ->> Network: exit successful, stake unlocked - - ``` ## Confirmation rules @@ -220,10 +209,7 @@ Below, we outline the stages of confirmation. 6. In a proven block that has been verified / validated by the L1 rollup contracts 7. In a proven block that has been finalized on the L1 -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone as User @@ -243,15 +229,11 @@ Contract --> Contract: waits N more blocks Contract --> Contract: finalizes block Network --> Contract: updates state to reflect finality Anyone ->> Network: confirms on their own node or block explorer - ``` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid journey title Wallet use case, basic transfer (tx confirmation happy path) section User Device @@ -264,7 +246,6 @@ journey section L1 Tx in block verified on L1: 6: Sequencer Tx in block finalized on L1: 7: Sequencer - ``` ## Economics @@ -306,10 +287,7 @@ Initially it's expected that the negotiations and commitment could be facilitate I'm not fully understanding the different groups, is the aztec network just the node software or 👀? Maybe coloring is nice to mark what is contracts and entities or groups of entities. Otherwise seems quite nice. ::: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone @@ -319,7 +297,7 @@ participant Sequencers participant Provers Anyone ->> Contract: register() -Anyone --> Anyone: Wait 7 days +Anyone --> Anyone: Wait epoch Anyone ->> Network: eligible as a sequencer loop Happy Path Block Production Sequencers --> Sequencers: Generate random hashes and rank them @@ -337,18 +315,14 @@ loop Happy Path Block Production Note right of Contract: "block confirmed!" end Sequencers ->> Contract: exit() -Sequencers --> Sequencers: wait 7 days - +Sequencers --> Sequencers: wait epoch ``` ### Voting on upgrades In the initial implementation of Aztec, sequencers may vote on upgrades alongside block proposals. If they wish to vote alongside an upgrade, they signal by updating their client software or an environment configuration variable. If they wish to vote no or abstain, they do nothing. Because the "election" is randomized, the voting acts as a random sampling throughout the current sequencer set. This implies that the specific duration of the vote must be sufficiently long and RANDAO sufficiently randomized to ensure that the sampling is reasonably distributed. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Contract as Aztec L1 Contract @@ -371,17 +345,13 @@ loop Happy Path Block Production Contract --> Contract: validates proofs and state transition Note right of Contract: "block confirmed! votes counted for upgrade!" end - ``` ### Backup mode In the event that no one submits a valid block proposal, we introduce a "backup" mode which enables a first come first serve race to submit the first proof to the L1 smart contracts. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone @@ -398,7 +368,6 @@ loop Happy Path Block Production Contract --> Contract: validates proofs and state transition Note right of Contract: "block confirmed!" end - ``` :::danger @@ -407,10 +376,7 @@ There is an outstanding concern that this may result in L1 censorship. L1 builde We also introduce a similar backup mode in the event that there is a valid proposal, but no valid prover commitment (deposit) by the end of the prover commitment phase. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Anyone @@ -431,7 +397,6 @@ loop Happy Path Block Production Contract --> Contract: validates proofs and state transition Note right of Contract: "block confirmed!" end - ``` ## Glossary diff --git a/docs/docs/protocol-specs/decentralization/governance.md b/docs/docs/protocol-specs/decentralization/governance.md index c4484f26e81..ee7208b76f9 100644 --- a/docs/docs/protocol-specs/decentralization/governance.md +++ b/docs/docs/protocol-specs/decentralization/governance.md @@ -128,10 +128,7 @@ Importantly we differentiate between `Aztec Governance`, and the governance of a ### Happy path -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Current Canonical Rollup as Current Rollup @@ -155,17 +152,13 @@ Version Registry ->> Version Registry: markPendingCanonical(nextRollup) Note right of Version Registry: Wait at least 30 days! Next Rollup ->> Version Registry: markCanonical(nextRollup) Sequencers ->> Next Rollup: Proposing new blocks here! - ``` ### "Bricked" rollup proposals In this diagram, we articulate the scenario in which the current canonical rollup contains bugs that result in it being unable to produce not only a block, but a vote of any kind. In this scenario, someone or a group (Lasse refers to as the "unbrick DAO") may lock 1% (specific # TBD) of total supply in order to propose a new canonical rollup. It is expected that this scenario is very unlikely, however, we believe it to be a nice set of checks and balances between the token holders and the decisions of the current rollup implementation. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Current Canonical Rollup as Current Rollup @@ -185,7 +178,6 @@ Note right of Version Registry: Wait at least 30 days! Note left of Sequencers: Upgrade to new client Next Rollup ->> Version Registry: markCanonical(nextRollup) Sequencers ->> Next Rollup: Proposing new blocks here! - ``` ### Vote Delegation @@ -198,10 +190,7 @@ Any token holder can delegate their token's voting weight to another address, in The diagram below articulates calling delegateTo(address) on both the governance contract and specifying a particular address. Additionally calling delegateTo() on the current canonical rollup if you wish to align with whatever voting mechanism that system currently as in place. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram participant Current Canonical Rollup as Current Rollup @@ -229,7 +218,6 @@ Version Registry ->> Version Registry: markPendingCanonical(nextRollup) Note right of Version Registry: Wait at least 30 days! Next Rollup ->> Version Registry: markCanonical(nextRollup) Sequencers ->> Next Rollup: Proposing new blocks here! - ``` ## Emergency mode diff --git a/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md b/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md index 47ad4edb8f9..738c4ba5ffe 100644 --- a/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md +++ b/docs/docs/protocol-specs/gas-and-fees/kernel-tracking.md @@ -16,10 +16,7 @@ On the private side, the ordering of the circuits is: The structs are (irrelevant fields omitted): -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class PrivateContextInputs { @@ -147,7 +144,7 @@ class PrivateKernelTailToPublicCircuitPrivateInputs { +PrivateKernelData previous_kernel } PrivateKernelTailToPublicCircuitPrivateInputs --> PrivateKernelData - + ``` ## Private Context Initialization @@ -275,10 +272,7 @@ On the public side, the order of the circuits is: The structs are (irrelevant fields omitted): -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class Gas { @@ -411,7 +405,7 @@ class GasFees { +Fr fee_per_da_gas +Fr fee_per_l2_gas } - + ``` ## Public Context Initialization diff --git a/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md b/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md index cede01d0c09..274afac824f 100644 --- a/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md +++ b/docs/docs/protocol-specs/gas-and-fees/specifying-gas-fee-info.md @@ -8,10 +8,7 @@ When users submit a `TxExecutionRequest` on the Aztec Network, they provide a `T An abridged version of the class diagram is shown below: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class TxExecutionRequest { +TxContext txContext @@ -41,7 +38,6 @@ class GasFees { TxContext --> GasSettings GasSettings --> Gas GasSettings --> GasFees - ``` :::note @@ -77,10 +73,7 @@ Separately, the **protocol** specifies the current `feePerGas` for each dimensio These are held in the L2 blocks `Header` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class Header { +GlobalVariables globalVariables @@ -100,7 +93,6 @@ class GasFees { Header --> GlobalVariables GlobalVariables --> GasFees - ``` A transaction cannot be executed if the `maxFeesPerGas` is less than the `feePerGas` for any dimension. diff --git a/docs/docs/protocol-specs/intro.md b/docs/docs/protocol-specs/intro.md index f9842bd3ead..58966b25c73 100644 --- a/docs/docs/protocol-specs/intro.md +++ b/docs/docs/protocol-specs/intro.md @@ -26,10 +26,7 @@ To increase the probability of diagrams being up-to-date we encourage you to wri You simply create a codeblock specifying the language as `mermaid` and write your diagram in the codeblock. For example: ````txt -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A --> B B --> C @@ -37,10 +34,7 @@ graph LR ``` ```` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A --> B B --> C @@ -52,10 +46,7 @@ Mermaid supports multiple types of diagrams, so finding one that suits your need When writing class diagrams, we recommend using the `classDiagram` type and composition arrows `*--` to represent extensions. Also for the sake of readability, add all the components in the class itself, including composite types. For example: ````txt -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class A{ foo: Bar @@ -74,10 +65,7 @@ classDiagram ``` ```` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class A{ foo: Bar diff --git a/docs/docs/protocol-specs/l1-smart-contracts/index.md b/docs/docs/protocol-specs/l1-smart-contracts/index.md index db1326fede2..845c77e36aa 100644 --- a/docs/docs/protocol-specs/l1-smart-contracts/index.md +++ b/docs/docs/protocol-specs/l1-smart-contracts/index.md @@ -63,10 +63,7 @@ For more information around the requirements we have for the availability, see [ Using the data structures defined throughout the [rollup circuits](./../rollup-circuits/index.md) section, we can outline the validating light node structure as follows: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram class Inbox { @@ -88,7 +85,6 @@ class StateTransitioner { StateTransitioner --> Inbox: consume() StateTransitioner --> Outbox: insert() StateTransitioner --> Verifier: verify() - ``` ### State transitioner @@ -481,10 +477,7 @@ Below, we will outline the **LOGICAL** execution of a L2 block and how the contr We will be executing cross-chain communication before and after the block itself. Note that the L2 inbox only exists conceptually and its functionality is handled by the kernel and the rollup circuits. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid sequenceDiagram autonumber title Logical Interactions of Crosschain Messages @@ -547,7 +540,6 @@ sequenceDiagram P->>O: Consume a msg O->>O: Validate msg O->>O: Update state (nullify) - ``` We will walk briefly through the steps of the diagram above. diff --git a/docs/docs/protocol-specs/rollup-circuits/base-rollup.md b/docs/docs/protocol-specs/rollup-circuits/base-rollup.md index 32df2e70bf4..a4859a4b4f4 100644 --- a/docs/docs/protocol-specs/rollup-circuits/base-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/base-rollup.md @@ -6,23 +6,16 @@ The base rollup circuit is the most complex of the rollup circuits, as it has to Take `BaseRollupInputs` as an input value, and transform it to `BaseOrMergeRollupPublicInputs` as an output value while making sure that the validity conditions are met. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A[BaseRollupInputs] --> C[BaseRollupCircuit] --> B[BaseOrMergeRollupPublicInputs] - ``` ## Overview Below is a subset of the figure from [earlier](./index.md) (granted, not much is removed). The figure shows the data structures related to the Base Rollup circuit. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -233,7 +226,6 @@ class BaseOrMergeRollupPublicInputs { BaseOrMergeRollupPublicInputs *-- ConstantRollupData : constants BaseOrMergeRollupPublicInputs *-- PartialStateReference : start BaseOrMergeRollupPublicInputs *-- PartialStateReference : end - ``` :::warning TODO diff --git a/docs/docs/protocol-specs/rollup-circuits/index.md b/docs/docs/protocol-specs/rollup-circuits/index.md index 1c7ca403926..d85df805dd2 100644 --- a/docs/docs/protocol-specs/rollup-circuits/index.md +++ b/docs/docs/protocol-specs/rollup-circuits/index.md @@ -33,10 +33,7 @@ And for the message parity we have: In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. Exactly how many layers and what combination of `base` and/or `merge` circuits are consumed is based on filling a [wonky tree](../state/tree-implementations.md#wonky-merkle-trees) with N transactions. Circles mark the different types of proofs, while squares mark the different circuit types. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R_p((Root)) R_c[Root] @@ -139,7 +136,6 @@ graph BT style I1 fill:#1976D2; style I2 fill:#1976D2; style I3 fill:#1976D2; - ``` To understand what the circuits are doing and what checks they need to apply it is useful to understand what data is going into the circuits and what data is coming out. @@ -153,10 +149,7 @@ Note that the diagram does not include much of the operations for kernels, but m -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -433,10 +426,7 @@ If this is not the case, the kernel proof might be valid, but the state changes It is therefore of the highest importance that the circuits ensure that the state is progressed correctly across circuit types and proofs. Logically, taking a few of the kernels from the above should be executed/proven as shown below, $k_n$ applied on top of the state that applied $k_{n-1}$ -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR SM[State Machine] S0((State n-1)) @@ -478,10 +468,7 @@ We can do so by building merkle trees of partial "commitments", whose roots are Below, we outline the `TxsHash` merkle tree that is based on the `TxEffect`s and a `OutHash` which is based on the `l2_to_l1_msgs` (cross-chain messages) for each transaction, with four transactions in this rollup. While the `TxsHash` implicitly includes the `OutHash` we need it separately such that it can be passed to the `Outbox` for consumption by the portals with minimal work. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R[TxsHash] M0[Hash 0-1] @@ -515,10 +502,7 @@ graph BT K7 --> B3 ``` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R[OutHash] M0[Hash 0-1] @@ -568,10 +552,7 @@ graph BT K15 --> K7 ``` -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R[InHash] M0[Hash 0-1] diff --git a/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md b/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md index b63ac550b3d..5d8ce56943f 100644 --- a/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/merge-rollup.md @@ -4,23 +4,16 @@ title: Merge Rollup The Merge rollup circuit is our in-between circuit, it doesn't need to perform any state updates, but mainly check the consistency of its inputs. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A[MergeRollupInputs] --> C[MergeRollupCircuit] --> B[BaseOrMergeRollupPublicInputs] - ``` ## Overview Below is a subset of the data structures figure from earlier for easy reference. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -75,7 +68,6 @@ class MergeRollupInputs { } MergeRollupInputs *-- ChildRollupData: left MergeRollupInputs *-- ChildRollupData: right - ``` ### Validity Conditions diff --git a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md index f4185de2b89..0e09c4663ff 100644 --- a/docs/docs/protocol-specs/rollup-circuits/root-rollup.md +++ b/docs/docs/protocol-specs/rollup-circuits/root-rollup.md @@ -4,13 +4,9 @@ title: Root Rollup The root rollup circuit is our top circuit, it applies the state changes passed through its children and the cross-chain messages. Essentially, it is the last step that allows us to prove that the state transition function $\mathcal{T}(S, B) \mapsto S'$ was applied correctly for a state $S$ and a block $B$. Note, that the root rollup circuit's public inputs do not comprise the block entirely as it would be too costly to verify. Given a `ProvenBlock` and proof a node can derive the public inputs and validate the correctness of the state progression. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph LR A[RootRollupInputs] --> C[RootRollupCircuit] --> B[RootRollupPublicInputs] --> D[ProvenBlock] --> E[Node] - ``` For rollup purposes, the node we want to convince of the correctness is the [validating light node](../l1-smart-contracts/index.md) that we put on L1. We will cover it in more detail in the [cross-chain communication](../l1-smart-contracts/index.md) section. @@ -21,10 +17,7 @@ This might practically happen through a series of "squisher" circuits that will ## Overview -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -170,7 +163,6 @@ class RootRollupPublicInputs { header: Header } RootRollupPublicInputs *--Header : header - ``` ### Validity Conditions diff --git a/docs/docs/protocol-specs/rollup-circuits/tree-parity.md b/docs/docs/protocol-specs/rollup-circuits/tree-parity.md index 6760e987757..77ec759a851 100644 --- a/docs/docs/protocol-specs/rollup-circuits/tree-parity.md +++ b/docs/docs/protocol-specs/rollup-circuits/tree-parity.md @@ -14,10 +14,7 @@ As earlier we are using a tree-like structure. Instead of having a `base`, `merge` and `root` circuits, we will have only `base` and `root` parity circuits. We only need these two, since what would have been the `merge` is doing the same as the `root` for this case. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R((RootParity)) @@ -64,7 +61,6 @@ style I0 fill:#1976D2; style I1 fill:#1976D2; style I2 fill:#1976D2; style I3 fill:#1976D2; - ``` The output of the "combined" circuit will be the `converted_root` which is the root of the snark-friendly message tree. @@ -72,10 +68,7 @@ And the `sha_root` which must match the root of the sha256 message tree from the The circuit computes the two trees using the same inputs, and then we ensure that the elements of the trees match the inbox later in the [state transitioner](./../l1-smart-contracts/index.md#overview). It proves parity of the leaves in the two trees. -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction LR @@ -100,7 +93,6 @@ RootParityInput *-- ParityPublicInputs: public_inputs class BaseParityInputs { msgs: List~Fr[2]~ } - ``` The logic of the circuits is quite simple - build both a SHA256 and a snark-friendly tree from the same inputs. diff --git a/docs/docs/protocol-specs/state/archive.md b/docs/docs/protocol-specs/state/archive.md index fd58b820670..459cea3b924 100644 --- a/docs/docs/protocol-specs/state/archive.md +++ b/docs/docs/protocol-specs/state/archive.md @@ -43,10 +43,7 @@ Therefore, we can probably remove the `contract_tree` and `ContractData` referen -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -125,5 +122,4 @@ class ArchiveTree { leaves: List~Header~ } ArchiveTree *.. "m" Header : leaves - ``` diff --git a/docs/docs/protocol-specs/state/index.md b/docs/docs/protocol-specs/state/index.md index ac11c1fd998..4dd342cfb80 100644 --- a/docs/docs/protocol-specs/state/index.md +++ b/docs/docs/protocol-specs/state/index.md @@ -83,10 +83,7 @@ To recall, the global state in Aztec is represented by a set of Merkle trees: th -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid classDiagram direction TB @@ -211,7 +208,6 @@ State *-- ArchiveTree : archive_tree State *-- NoteHashTree : note_hash_tree State *-- NullifierTree : nullifier_tree State *-- PublicDataTree : public_data_tree - ``` import DocCardList from '@theme/DocCardList'; diff --git a/docs/docs/protocol-specs/state/tree-implementations.md b/docs/docs/protocol-specs/state/tree-implementations.md index b40a5557d65..dfeded6c824 100644 --- a/docs/docs/protocol-specs/state/tree-implementations.md +++ b/docs/docs/protocol-specs/state/tree-implementations.md @@ -20,7 +20,7 @@ Indexed Merkle trees, introduced [here](https://eprint.iacr.org/2021/1263.pdf), With an Indexed Merkle tree, proving non-membership of a value `x` then requires a membership proof of the node with value lower than `x` and a next-highest value greater than `x`. The cost of this proof is proportional to the height of the tree, which can be set according to the expected number of elements to be stored in the tree. For comparison, a non-membership proof in a sparse tree requires a tree with height proportional to the size of the elements, so when working with 256-bit elements, 256 hashes are required for a proof. -Refer to [this page](../../aztec/concepts/storage/trees/indexed_merkle_tree.mdx) for more details on how insertions, updates, and membership proofs are executed on an Indexed Merkle tree. +Refer to [this page](../state/tree-implementations.md#indexed-merkle-trees) for more details on how insertions, updates, and membership proofs are executed on an Indexed Merkle tree. diff --git a/docs/docs/protocol-specs/state/wonky-tree.md b/docs/docs/protocol-specs/state/wonky-tree.md index fb7953f470d..093e7334e5e 100644 --- a/docs/docs/protocol-specs/state/wonky-tree.md +++ b/docs/docs/protocol-specs/state/wonky-tree.md @@ -4,10 +4,7 @@ A 'wonky' tree is an append-only unbalanced merkle tree, filled from left to rig For example, using a balanced merkle tree to rollup 5 transactions requires padding of 3 empty transactions: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R_c[Root] @@ -62,10 +59,7 @@ Where each node marked with `*` indicates a circuit proving entirely empty infor Our wonky tree implementation instead gives the below structure for 5 transactions: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R_c[Root] @@ -106,10 +100,7 @@ graph BT Here, each circuit is proving useful transaction information with no wasted compute. We can construct a tree like this one for any number of transactions by greedy filling from left to right. Given the required 5 base circuits: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph B0_c[Base 0] B1_c[Base 1] @@ -120,10 +111,7 @@ graph ...we theh pair these base circuits up to form merges: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT M0_c[Merge 0] M1_c[Merge 1] @@ -142,10 +130,7 @@ graph BT Since we have an odd number of transactions, we cannot pair up the final base. Instead, we continue to pair the next layers until we reach a layer with an odd number of members. In this example, that's when we reach merge 2: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT M0_c[Merge 0] M1_c[Merge 1] @@ -168,10 +153,7 @@ graph BT Once paired, the base layer has length 4, the next merge layer has 2, and the final merge layer has 1. After reaching a layer with odd length, the orchestrator can now pair base 4: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT R_c[Root] @@ -230,10 +212,7 @@ Subtrees: [16, 8, 4, 2, 1] -> An unrolled recursive algorithm is not the easiest thing to read. This diagram represents the 31 transactions rolled up in our wonky structure, where each `Merge ` is a 'subroot' above: -```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - +```mermaid graph BT M2_c[Merge 2] M3_c[Merge D @@ -327,10 +306,7 @@ Here is a step-by-step example to construct the _`block_logs_data`_: 1. A rollup, _R01_, merges two transactions: _tx0_ containing _tx_logs_data_0_, and _tx1_ containing _tx_logs_data_1_: - ```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - + ```mermaid flowchart BT tx0((tx0)) tx1((tx1)) @@ -345,10 +321,7 @@ import { Mermaid } from '@docusaurus/theme-mermaid'; 2. Another rollup, _R23_, merges two transactions: _tx3_ containing _tx_logs_data_3_, and _tx2_ without any logs: - ```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - + ```mermaid flowchart BT tx2((tx2)) tx3((tx3)) @@ -363,10 +336,7 @@ import { Mermaid } from '@docusaurus/theme-mermaid'; 3. A rollup, _RA_, merges the two rollups _R01_ and _R23_: - ```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - + ```mermaid flowchart BT tx0((tx0)) tx1((tx1)) @@ -389,10 +359,7 @@ import { Mermaid } from '@docusaurus/theme-mermaid'; 4. A rollup, _RB_, merges the above rollup _RA_ and another rollup _R45_: - ```mdx -import { Mermaid } from '@docusaurus/theme-mermaid'; - - + ```mermaid flowchart BT tx0((tx0)) tx1((tx1)) diff --git a/docs/docs/reference/index.md b/docs/docs/reference/index.md deleted file mode 100644 index 2b725e63ad9..00000000000 --- a/docs/docs/reference/index.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: References -sidebar_position: 0 ---- - -# References - -Welcome to the References section! In this section you will find reference material for developing on Aztec Protocol. - -This page lists popular references. Please see the sidebar for them all. - - -## Popular - -### Smart contracts - -
- - - -

Storage

-
- - A detailed reference for storage types - -
- - - -

Portals

-
- - A detailed reference for working with portals and L1/L2 communication - -
- -
- -### Others - -
- - - -

Common Sandbox Errors

-
- - Help debug your sandbox environment - -
- - - -

CLI reference

-
- - A full list of commands for working with the Aztec CLI - -
-
- - diff --git a/docs/docs/run_node/concepts/_category_.json b/docs/docs/run_node/concepts/_category_.json new file mode 100644 index 00000000000..19d79cf9e98 --- /dev/null +++ b/docs/docs/run_node/concepts/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true, + "label": "Decentralization Concepts" +} diff --git a/docs/docs/guides/developer_guides/running_nodes/_category_.json b/docs/docs/run_node/concepts/deployments/_category_.json similarity index 51% rename from docs/docs/guides/developer_guides/running_nodes/_category_.json rename to docs/docs/run_node/concepts/deployments/_category_.json index 88c8b42bc8f..03142f5a9e8 100644 --- a/docs/docs/guides/developer_guides/running_nodes/_category_.json +++ b/docs/docs/run_node/concepts/deployments/_category_.json @@ -1,6 +1,6 @@ { - "position": 5, + "position": 2, "collapsible": true, "collapsed": true, - "label": "Aztec Protocol" + "label": "Deployments" } diff --git a/docs/docs/run_node/concepts/deployments/what_is_deployment.md b/docs/docs/run_node/concepts/deployments/what_is_deployment.md new file mode 100644 index 00000000000..cd691a0036a --- /dev/null +++ b/docs/docs/run_node/concepts/deployments/what_is_deployment.md @@ -0,0 +1,244 @@ +--- +sidebar_position: 0 +title: What is a Deployment? +--- + +An Aztec deployment is a set of the following contracts: + +| Smart Contract | Immutability | +|--------------------------------|--------------| +| Hypothetical Asset | Immutable | +| Issuer Contract | Immutable | +| Registry Contract | Immutable | +| Reward Distribution Contract | Mutable | +| Proposals Contract | Mutable | +| Governance Contract | Immutable | +| Rollup Contract | Immutable | + +## Hypothetical Asset Contract + +Hypothetical Asset would live on Ethereum L1. It may have a minter which would be the only actor capable of calling the `mint` function on the Hypothetical Asset contract. + +This is brought up to the community for discussion purposes only to illustrate how proposed governance mechanisms could work with a Hypothetical Asset. + +- **Validators** must stake the Hypothetical Asset within the instance's contract to join that instance's validator set. +- **Holders** must lock Hypothetical Asset with the Governance contract to be able to vote on proposals. +- **Provers** must deposit Hypothetical Asset in the escrow contract in order to bid for the right to create a proof for an epoch. + +## Issuer Contract + +This contract will be the sole minter of Hypothetical Asset. It will itself have an owner, which is the only actor capable of calling the `mint` function on the Hypothetical Asset ERC20 contract. + +The `mint` function will limit the amount of Hypothetical Assets that could be minted in a given time period. The reasoning behind this limit is that it makes supply expansions more predictable since "infinite mints" cannot be made. + +```mermaid +flowchart LR + Issuer -->|Calls mint| HypotheticalAsset +``` + +```solidity +contract Issuer is Ownable { + ERC20 immutable public ASSET; // Hypothetical Asset + uint256 immutable public RATE; + uint256 public timeOfLastMint; + + constructor(ERC20 _asset, uint256 _rate, address _owner) Ownable(_owner) { + ASSET = _asset; + RATE = _rate; + timeOfLastMint = block.timestamp; + } + + function mint(address _to, uint256 _amount) external onlyOwner { + uint256 maxMint = RATE * (block.timestamp - timeOfLastMint); + require(_amount <= maxMint, 'Insufficient mint available'); + + timeOfLastMint = block.timestamp; + ASSET.mint(_to, _amount); + } +} +``` + +## Registry Contract + +The governance of Aztec will be community driven - the Aztec community will be able to decide whether to upgrade or migrate to a new rollup instance. Portals / apps donʼt need to follow along with the Aztec governance and can specify the specific instance (i.e. “versionˮ) of the rollup that they view as canonical. + +Therefore it will be necessary to keep track onchain of what versions of the rollup have existed as well as what version the Aztec governance views as the current canonical rollup. Only the current canonical rollup from the perspective of Aztec governance will be eligible to claim any further Hypothetical Asset rewards. + +```mermaid +flowchart LR + Registry --> RollupContract0["Rollup Contract
Instance 0"] + Registry --> RollupContract1["Rollup Contract
Instance 1"] + Registry --> |Returns latest instance|RollupContractN["Rollup Contract
Instance n"] +``` +In practice, the Registry is an array of rollup instances that can only be inserted into by the Registryʼs owner - the Governance contract. + +```solidity +contract Registry is IRegistry, Ownable { + struct Instance { + address rollup; + uint96 blockNumber; + } + + Instance[] public instances; + + constructor(address _gov) Ownable(_gov) { + instances.push( + Instance({address: address(0), blockNumber: block.number}) + ); + } + + function addInstance(address _rollup) external onlyOwner { + instances.push( + Instance({address: _rollup, blockNumber: block.number}) + ); + } + + function getRollup() external view returns (address) { + return instances[instances.length - 1].rollup; + } + + function getInstancesLength() external view returns (uint256) { + return instances.length; + } +} +``` + +## Reward Distribution Contract + +This contract distributes ERC20 rewards only to the instance the Registry contract says is canonical. This is separated from the Registry and the Issuer so that the distribution logic can be changed without replacing the Registry. + +In practice, the flow is expected to be such that infrequently, the Aztec Governance votes that the Issuer smart contract mints a quantity of Hypothetical Asset and sends them to the Distribution contract. The rollup contract will call the `claim(_to)` on the Distribution contract which checks that the calling Rollup is the current canonical Rollup before releasing a Hypothetical Asset to the rollup. + +The Rollup smart contract implements custom logic for how to split `BLOCK_REWARDS` amongst the proposers/committee/provers who provide real work in the form of electricity and hardware intensive computational resources to the Rollup smart contract. + +```mermaid +flowchart TD + Issuer -->|1. Calls mint| HypotheticalAsset + Issuer -->|2. Transfer Hypothetical Asset| RewardDistribution + RollupContract -->|3. Calls claim| RewardDistribution +``` + +```solidity +contract RewardDistribution is Ownable { + uint256 public constant BLOCK_REWARD = xxx; + + IERC20 public immutable ASSET; + IRegistry public registry; + + // constructor etc + + function claim(address _to) external returns (uint256) { + address canonical = registry.getRollup(); + require(msg.sender == canonical); + ASSET.safeTransfer(_to, BLOCK_REWARD); + return BLOCK_REWARD; + } + + function updateRegistry(IRegistry _registry) external onlyOwner { + // ... + } +} +``` + +Rollup contacts implementations should not revert if the `claim()` call reverts because the rollup is no longer canonical. Otherwise, no one could sequence the rollup anymore. + +The separation of Distribution and Issuer is primarily for code hygiene purposes. + +The protocol inflation rate is defined in the Issuer smart contract as the constant `RATE`. It is not possible to change this inflation rate once the Issuer smart contract has been deployed. Aztec Governance can vote on a proposal to deploy a new Issuer smart contract that contains a new `RATE` + +The Aztec Governance will choose how often to call `mint()` on the Issuer smart contract which will send any Hypothetical Assets to the Distribution smart contract. The Distribution smart contract defines a `BLOCK_REWARD` constant value (again cannot be changed). Every epoch, the Rollup contract can call the Distribution smart contract to claim `BLOCK_REWARD` of Hypothetical Assets from the Distribution contract. + +Both `RATE` and `BLOCK_REWARD` will be set upon deployment of the Aztec Rollup by the Aztec Governance. Both values are immutable and cannot be changed without re-deploying a new smart contract and a successful vote by Aztec Governance to switch to the new smart contracts. + +## Proposals contract + +This is the only smart contract that is able to submit proposals to the Governance contract. + +The Proposals Contract will accept proposals only from sequencers of the current canonical instance, as indicated by the Registry. + +```solidity +contract Proposals is IProposals { + + // ... imports + + IGovernance public immutable GOVERNANCE; + IRegistry public immutable REGISTRY; + uint256 public immutable N; + uint256 public immutable M; + + constructor(IGovernance _governane, IRegistry _registry, uint256 _n, uint256 _m) { + // ... + + require(N > M / 2); + require(N <= M); + } + + function vote(address _proposal) external override(IProposals) returns (bool) { + require(_proposal.code.length > 0); + // ... + + Rollup instance = Rollup(REGISTRY.getRollup()); + address proposer = instance.getCurrentProposer(); + require(msg.sender == proposer); + } + // ... +} +``` +To vote to table a proposal, the current sequencer of the canonical rollup must deploy the contracts being proposed to upgrade / migrate to, to the L1. Then the current sequencer deploys the upgrade logic i.e. `_proposal`, then call `Proposals.vote(_proposal)`. + +The Proposals contract will then count votes specifying that same `_proposal`. For a proposal to be nominated for voting, it must garner at least N votes in a single round, where a round is defined as a M consecutive L2 slots. Round 1 is L2 slots 0 - M - 1, while Round 2 is L2 slots M - 2M - 1 and so on. + +Note that a sequencer’s ability to vote is not affected by the rollupʼs availability since voting happens on the L1. + +```mermaid +flowchart TD + Issuer[Issuer] -->|1. Calls mint| HypotheticalAsset[Hypothetical Asset] + Issuer -->|2. Transfer Hypothetical Asset| RewardDistribution[Reward Distribution] + RewardDistribution -->|3. Calls claim| RollupContract[RollupContract] +``` + +If the quorum has been reahed, anyone can call `pushProposal(uint256 _roundNumber)` on the Proposals contract to send the proposal to the Governance contract for voting. As a result, only one proposal can be nominated for voting at any given round. + +## Governance contract + +This contract is the “assembly of Aztec citizensˮ that is the final arbiter of whether to enact the proposals from the Proposals Contract or not. + +This contract decides what is the canonical instance which gets block rewards. + +The Proposals contract tables proposals for voting, Holders who lock their Hypothetical Assets with the Governance contract may vote once for each Hypothetical Asset locked. They can vote either Yea or Nea. + +Once a proposal garners the minimum number of votes, and the Yay votes exceed Nay by at least the `quorum%` , the proposal can be executed by the Governance contract. + +```solidity +contract Governance is IGovernance { // ... imports + IERC20 public immutable ASSET; address public proposalsContract; // ... + constructor(IERC20 _asset, address _proposalsContract, ui nt256 _votingDelay, uint256 _votingDuration, uint256 _gracePeriod, uint256 _quorum, uin t256 _voteDifferential, uint256 _minimumVotes) { // ... + configuration = DataStructures.Configuration({ votingDelay: Timestamp.wrap(_votingDelay), // Min time between proposal creation and when voting starts votingDuration: Timestamp.wrap(_votingDuration), // Max duration of voting period + executionDelay: Timestamp.wrap(_executionDelay), // Min time between voting passing and proposal execution gracePeriod: Timestamp.wrap(_gracePeriod), // max time between proposal creation and proposal execution. + quorum: _quorum, // % of deposited ASSET that mus t participate in a vote (could be Yes or No) voteDifferential: _voteDifferential, // Yea must outweight Nea by this % to pass vote minimumVotes: _minimumVotes, // users with this much cummulative deposited ASSET must participate in the vote }) + } +// ... +function deposit(address _onBehalfOf, uint256 _amount) external override(IGovernance) { + // deposits are allowed on behalf of other addresses + users[_onBehalfOf].add(_amount); + // ... +} + +function initiateWithdraw(address _to, uint256 _amount) external override(IGovernance) returns (uint256) { + // ... + // No one can withdraw on behalf of someone else + users[msg.sender].sub(_amount); + // ... +} + +function propose(address _payload) external override(IGovernance) returns (bool) { + require(msg.sender == proposalsContract); + // ... +} + +function vote(uint256 _proposalId, uint256 _amount, bool _support) external override(IGovernance) returns (bool) {} + +function execute(uint256 _proposalId) external override(IGovernance) returns (bool) { + // execute proposal via `call()` +} +``` diff --git a/docs/docs/run_node/concepts/governance/_category_.json b/docs/docs/run_node/concepts/governance/_category_.json new file mode 100644 index 00000000000..69efe5a1496 --- /dev/null +++ b/docs/docs/run_node/concepts/governance/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 1, + "collapsible": true, + "collapsed": true, + "label": "Governance" +} diff --git a/docs/docs/run_node/concepts/governance/governance.md b/docs/docs/run_node/concepts/governance/governance.md new file mode 100644 index 00000000000..7669574ddd4 --- /dev/null +++ b/docs/docs/run_node/concepts/governance/governance.md @@ -0,0 +1,17 @@ +--- +id: governance +sidebar_position: 3 +title: Governance Overview +--- + +import Image from "@theme/IdealImage"; + +This diagram outlines how governance works on Aztec: + + + +Sequencers put forward, or “nominate”, proposals for voting by the Aztec citizens. To do this, sequencers interact with the Governance Proposer smart contract. Nominations are “signals” by sequencers that they wish to put up for vote the execution of certain code by the Governance smart contract. + +If the Governance Proposer smart contract records a certain number of nominations/signals from sequencers, then the Governance Proposer smart contract initiates a voting process where any holders of any Hypothetical Assets (as defined below) can participate. Holders of such Hypothetical Assets are called Aztec citizens. + +All voting and signalling happen on the L1. diff --git a/docs/docs/run_node/concepts/governance/putting_forward_proposals.md b/docs/docs/run_node/concepts/governance/putting_forward_proposals.md new file mode 100644 index 00000000000..b110899e453 --- /dev/null +++ b/docs/docs/run_node/concepts/governance/putting_forward_proposals.md @@ -0,0 +1,17 @@ +--- +sidebar_position: 0 +title: Putting forward Proposals +--- + +Sequencers of the *current* canonical rollup (as indicated by the Registry) can propose changes to the Aztec community for voting. In order for a proposal to be voted on through the governance process, *N* sequencers must nominate the proposal in any given round. A round is defined as a sequence of contiguous M L2 blocks. Both *N* and *M* are governance defined parameters. + +Sequencers can only nominate a proposal during an L1 slot for which they’ve been assigned proposer duties. This minimizes timing games and provides a lower bound on the time required to successfully bring about a vote by governance. + +A mechanism is also proposed whereby any digital asset (“Hypothetical Assetˮ) holder (“Holderˮ) can burn a large quantity of Hypothetical Asset to trigger a vote on a proposal, without having the sequencers nominating the proposal. Note that Hypothetical Asset holders would still need to vote to approve any proposals nominated via this mechanism. + +To nominate a proposal, a validator of the current canonical rollup would deploy two sets of contracts: +1. The upgraded contracts they wish to upgrade to +2. `code` which can be executed by governance to upgrade into these contracts + +Then when it is their turn as the proposer, they call `vote(address _proposal)` on the `Proposals` contract, where `_proposal ` is the address of the `code` payload. + diff --git a/docs/docs/run_node/concepts/governance/upgrades.md b/docs/docs/run_node/concepts/governance/upgrades.md new file mode 100644 index 00000000000..08bd1910cec --- /dev/null +++ b/docs/docs/run_node/concepts/governance/upgrades.md @@ -0,0 +1,38 @@ +--- +sidebar_position: 4 +title: Upgrades +--- + +Upgrades involve transitioning the network to a new instance of the Rollup contract. They might fix vulnerabilities, introduce new features, or enhance performance. + +## AZIP + +It is expected that the community will coordinate upgrade proposals via an AZIP process, which is a design document outlining the upgrade rationale and one that allows for collecting technical input from and by the community. + +Once developers of client software agree to support the upgrade, sequencers can begin signaling to table this proposal from a certain block height. + +## Initial Contract Deployment + +The initial deployment creates a set of contracts, as described in the [Deployment section](../deployments/what_is_deployment.md). + +## Upgrading the Rollup Contract + +1. **Proposal Creation:** + - A new Rollup contract is deployed to the network + - Proposal code to execute the upgrade is deployed separately + +2. **Governance Approval:** + - Governance contract holders vote to approve or reject the proposal. Votes are proportional to the amount of Hypothetical Asset locked in the Governance contract. + +3. **Sequencer Participation:** + - Sequencers must signal their readiness by voting through the Proposals contract. + - This vote occurs during their assigned L2 slot, as dictated by the L1 Rollup smart contract. + +## Proposal Execution + +After governance approval and a delay period, the proposal becomes executable: + +- Any Ethereum account can call `execute(_proposalId)` on the Governance contract. +- The `execute` function calls the proposal code, transitioning the network to the new Rollup instance. + +For a more hands-on guide to reacting to upgrades as a sequencer/validators, read [this](../../guides/reacting_to_upgrades.md). \ No newline at end of file diff --git a/docs/docs/run_node/concepts/governance/voting.md b/docs/docs/run_node/concepts/governance/voting.md new file mode 100644 index 00000000000..911e8826945 --- /dev/null +++ b/docs/docs/run_node/concepts/governance/voting.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 1 +title: Voting on Proposals +--- + +Holders have the ability to vote on proposals as long as they lock any Hypothetical Assets within the Governance contract. The act of locking the funds can be thought of as “activatingˮ the voting power of Hypothetical Asset. Locked Hypothetical Assets used to vote on a proposal must wait a delay before being withdrawn to prevent malicious governance attacks. + +Hypothetical Assets locked in the Governance contract are simply locked and not “at stakeˮ i.e. there are no slashing conditions. + +Since sequencers may be able to stake Hypothetical Assets with the rollup instances in order to join the validator set, the rollup instance could in turn lock those Hypothetical Assets in the Governance contract and vote on behalf of the sequencers. This is expected behavior. diff --git a/docs/docs/run_node/concepts/proof_of_stake/_category_.json b/docs/docs/run_node/concepts/proof_of_stake/_category_.json new file mode 100644 index 00000000000..b4fac2f6e6a --- /dev/null +++ b/docs/docs/run_node/concepts/proof_of_stake/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 3, + "collapsible": true, + "collapsed": true, + "label": "Proof of Stake" +} diff --git a/docs/docs/run_node/concepts/proof_of_stake/index.md b/docs/docs/run_node/concepts/proof_of_stake/index.md new file mode 100644 index 00000000000..1d5498bc3b6 --- /dev/null +++ b/docs/docs/run_node/concepts/proof_of_stake/index.md @@ -0,0 +1,7 @@ +--- +sidebar_position: 1 +title: Proof of Stake system +draft: true +--- + +This doc will be updated soon. \ No newline at end of file diff --git a/docs/docs/run_node/concepts/proof_of_stake/slashing.md b/docs/docs/run_node/concepts/proof_of_stake/slashing.md new file mode 100644 index 00000000000..f54eaf05aab --- /dev/null +++ b/docs/docs/run_node/concepts/proof_of_stake/slashing.md @@ -0,0 +1,52 @@ +--- +sidebar_position: 2 +title: Slashing +draft: true +--- + +We need to make sure that the chain is always (eventually) finalizing new blocks. +These conditions are required for the chain to finalize new blocks: + +1. More than 2/3 of the committee is making attestations +2. Provers are producing proofs. + +## Avoiding network halt + +There are some actions that impact the chainʼs ability to finalize new blocks: + +### Insufficient quorum + +In the event that a significant portion of the validator set goes offline (i.e. geopolitical emergency) and proposers are unable to get enough attestations on block proposals, the Aztec Rollup will be unable to finalize new blocks. This will require the community to engage to fix the issue and make sure new blocks are being finalized. + +In the event of a prolonged period where the Aztec Rollup is not finalizing new blocks, it may enter Based Fallback mode. The conditions that lead to [Based Fallback (forum link)](https://forum.aztec.network/t/request-for-comments-aztecs-block-production-system/6155) mode are expected to be well defined by the community of sequencers, provers, client teams and all other Aztec Rollup stakeholders and participants. + +During Based Fallback mode, anyone can propose blocks if they supply proofs for these blocks alongside them. This is in contrast to the usual condition that only the sequencer assigned to a particular slot can propose blocks during that slot. This means that the inactive validator set is bypassed and anyone can advance the chain in the event of an inactive / non-participating validator set. + +But terminally inactive validators must be removed from the validator set or otherwise we end up in Based Fallback too often. Slashing is a method whereby the validator set votes to “slash” the stake of inactive validators down to a point where they are kicked off the validator set. For example, if we set `MINIMUM_STAKING_BALANCE=50%` then as soon as 50% or more of a validator’s balance is slashed, they will be kicked out of the set. + +### Committee withholding data from the provers + +Provers need the transaction data (i.e. `TxObjects`) plus the client-side generated proofs to produce the final rollup proof, none of which are posted onchain. Client side proofs + transaction data are gossiped on the p2p instead so that committee members can re-execute block proposals and verify that the proposed state root is correct. + +Recall from the [RFC (forum link)](https://forum.aztec.network/t/request-for-comments-aztecs-block-production-system/6155) on block production that the committee is a subset of validators, randomly sampled from the entire validator set. Block proposers are sampled from this committee. ⅔ + 1 of this committee must attest to L2 block proposals before they are posted to the L1 by the block proposer. + +A malicious committee may not gossip the transaction data or proofs to the rest of the validator set, nor to the provers. As a result, no prover can produce the proof and the epoch in question will reorg by design.Recall from the RFC on block production that if no proof for epoch N is submitted to L1 by the end of epoch N+1, then epoch N + any blocks built in epoch N+1 are reorged. + +### Committee proposing an invalid state root + +Committee members who receive a block proposal from a proposer, must execute the block’s transaction to compare the resulting state root with that contained in the proposal. In theory, a committee member should only attest to a block proposal’s validity after checking for the correctness of the state root. + +A committee member could skip re-executing block proposals, for a number of reasons including saving compute, faulty client software or maliciousness. This opens up the possibility of a malicious proposer posting an invalid state transition to L1. Or a malicious entity that bribes ⅔ + 1 of the committee can obtain the required signatures to post an invalid state transition. +The epoch will not be proven and will be re-orged. + +### L1 congestion has made it impossible for provers to land proofs on time + +An honest prover who has funds at stake (i.e. posted a bond to produce the epoch proof), could be unable to post the proof on L1 due to congestion, an L1 reorg or just an inactivity of the L1 proposers (i.e. inactivity leak). + +## Slashing mechanism + +In all the previous cases, it is very hard to verify and automatically slash for these events onchain. This is mainly due to the fact that neither TxObjects nor client side proofs are posted onchain. Committee members also gossip attestations on the p2p and do not post them directly on chain. + +Therefore a slashing mechanism is required as a deterrence against the malicious behaviour by validators and to make sure that the Aztec Rollup retains liveness. The validator set votes to slash dishonest validators based on evidence that is collected onchain + offchain, and discussed and analyzed offchain (i.e. on a forum). + +A validator must aggregate BLS signatures on slashing proposals and post them to the L1 for slash execution. diff --git a/docs/docs/run_node/concepts/provers-and-sequencers/_category_.json b/docs/docs/run_node/concepts/provers-and-sequencers/_category_.json new file mode 100644 index 00000000000..24bb8c8ac10 --- /dev/null +++ b/docs/docs/run_node/concepts/provers-and-sequencers/_category_.json @@ -0,0 +1,7 @@ +{ + "position": 4, + "collapsible": true, + "collapsed": true, + "label": "Provers and Sequencers" +} + diff --git a/docs/docs/run_node/concepts/provers-and-sequencers/index.md b/docs/docs/run_node/concepts/provers-and-sequencers/index.md new file mode 100644 index 00000000000..262874206b5 --- /dev/null +++ b/docs/docs/run_node/concepts/provers-and-sequencers/index.md @@ -0,0 +1,14 @@ +--- +sidebar_position: 0 +title: Provers and Sequencers +--- + +## Block Production Overview + +Both sequencing and proving in the Aztec Network are intended to be fully decentralized. + +Sequencers will be chosen via a random election, while provers will be selected by sequencers via an out-of-protocol coordination mechanism. + +The proposers in the first `C=13` slots in epoch `N+1` will accept quotes to prove epoch N from provers. The winning prover will have until the end of epoch `N+1` to produce and submit the proof to L1. + +If are you interested in running a validator node (also known as a sequencer node) or a prover node, you can refer to [the guides section](./../../guides/run_nodes/index.md). diff --git a/docs/docs/run_node/concepts/provers-and-sequencers/proving_coordination_workflow.md b/docs/docs/run_node/concepts/provers-and-sequencers/proving_coordination_workflow.md new file mode 100644 index 00000000000..2b7f6ddebc6 --- /dev/null +++ b/docs/docs/run_node/concepts/provers-and-sequencers/proving_coordination_workflow.md @@ -0,0 +1,108 @@ +--- +sidebar_position: 1 +title: Proving Coordination Workflow +draft: true +--- + +Proposers run RFQs to obtain quotes from provers. Quotes are binding promises from provers to prove an entire epoch. The exact channel over which provers send quotes to proposers is **NOT** enshrined by the protocol. + +However, Aztec Nodes will support two optional mechanisms that provers can use to submit quotes to proposers: + +- Gossip quotes via the P2P +- Send a quote directly via HTTP (i.e. http://aztec-node:8000) + +To send a quote via the P2P, do not set the environment variable `PROVER_COORDINATION_NODE_URL` and make sure that `P2P_ENABLED` is set to `true`. + +:::note +For S&P Testnet, please make sure that you are gossiping quotes via the P2P. Set `P2P_ENABLED` to `true` and do not use `PROVER_COORDINATION_NODE_URL`. +::: + + +```rust +struct EpochProofQuote { + Signature signature; + address prover; + uint256 epochNumber; + uint256 epochInitBlock; + uint256 epochFinalBlock; + uint256 totalFees; + address rollupAddress; + uint32 basisPointFee; + uint256 bondAmount; +} +``` + +To accomplish this coordination through the Aztec node software, we extend both the `P2PClient` and `ProverNode`. + +## P2P client + +The `P2PClient` will be extended by: + +```typescript +class P2PClient { + //... + + async addEpochProofQuote(quote: EpochProofQuote): Promise { + // Add quote to quote memory pool + this.epochProofQuotePool.addQuote(quote); + + // Propagate quote via P2P + this.broadcastEpochProofQuote(quote); + } +} +``` + +This is called by the Prover Node inside `ProverNode.sendEpochProofQuote()` after it detects an epoch has ended. + +## Prover Node + +As for the Prover Node, we add `QuoteProvider` and `BondManager` interfaces. Also an `EpochMonitor` which sits on the main start loop of the Prover Node. It fetches the most recent completed epochs and checks whether the proposer accepted an `EpochProofQuote`. + +If no quote has been accepted yet, the `EpochMonitor` will call on `BondManager` and `QuoteProvider` to provide a valid quote. If the claim detected belongs to the prover, the monitor will kick off a `handleCall()` to create proving jobs. + +```typescript +interface BondManager { + ensureBond(amount: number): Promise; +} +interface QuoteProvider { + getQuote(epoch: number): Promise; +} +``` + +When the prover node first starts up, it will call `BondManager.ensureBond` to ensure it has the minimum deposit amount `PROVER_MINIMUM_ESCROW_AMOUNT` deposited in the escrow contract. If it does not, it will top up to the target deposit amount `PROVER_TARGET_ESCROW_AMOUNT`. + +Both `PROVER_MINIMUM_ESCROW_AMOUNT` and `PROVER_TARGET_ESCROW_AMOUNT` are customizable environment variables. + +The `EpochMonitor` will then get the last completed, unproven epoch and will call the `QuoteProvider` to generate a quote if the epoch has not been claimed by any provers yet. The `QuoteProvider` will be provided with all the blocks in the unproven epoch so it could perform any custom logic to determine the quote parameters, i.e., `bondAmount`, `basisPointFee`, etc. + +Alternatively, the quote provider can issue an HTTP POST to a configurable `QUOTE_PROVIDER_URL` to get the quote. The request body is JSON-encoded and contains the following fields: + +- `epochNumber`: The epoch number to prove +- `fromBlock`: The first block number of the epoch to prove +- `endBlock`: The last block number (inclusive) of the epoch to prove +- `txCount`: The total number of txs in the epoch +- `totalFees`: The accumulated total fees across all txs in the epoch + +The response is also expected in JSON and to contain `basisPointFee` and `bondAmount` fields. Optionally, the request can include a `validUntilSlot` parameter, which specifies for how many slots the quote remains valid. For example, an `EpochProofQuote` with parameters `epochProofQuote#80` and `validUntilSlot#5` means that any of the first 5 proposers in epoch 101 can “claim” this quote. + +If no `QUOTE_PROVIDER_URL` is passed along to the Prover Node, then a `SimpleQuoteProvider` is used, which always returns the same `basisPointFee` and `bondAmount` as set in the `QUOTE_PROVIDER_BASIS_POINT_FEE` and `QUOTE_PROVIDER_BOND_AMOUNT` environment variables. + +:::warning +If the `QuoteProvider` does not return a `bondAmount` or a `basisPointFee`, the Prover Node will not generate nor submit a quote to the proposer. +::: + +Separately, the Prover Node needs a watcher on L1 to detect if its quote has been selected. + +To this end, the `L1Publisher` will be extended with a new method to retrieve proof claims. + +```typescript +interface L1Publisher { + getProofClaim(): Promise; +} +``` + +The Prover Node will call this method at least once per L2 slot to check for unclaimed accepted quotes if its quotes have been accepted. You can update the polling interval using the environment variable `PROVER_NODE_POLLING_INTERVAL_MS`. + +## Run a prover + +Go to the [Prover Guide](../../guides/run_nodes/how_to_run_prover.md) to run a prover. \ No newline at end of file diff --git a/docs/docs/run_node/guides/_category_.json b/docs/docs/run_node/guides/_category_.json new file mode 100644 index 00000000000..5dc68949682 --- /dev/null +++ b/docs/docs/run_node/guides/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 2, + "collapsible": true, + "collapsed": true, + "label": "Guides" +} diff --git a/docs/docs/run_node/guides/connecting_to_node.md b/docs/docs/run_node/guides/connecting_to_node.md new file mode 100644 index 00000000000..32ccbcb2bfe --- /dev/null +++ b/docs/docs/run_node/guides/connecting_to_node.md @@ -0,0 +1,5 @@ +--- +sidebar_position: 0 +title: Connecting to a node +draft: true +--- \ No newline at end of file diff --git a/docs/docs/run_node/guides/node_reference.md b/docs/docs/run_node/guides/node_reference.md new file mode 100644 index 00000000000..4b45fbd9e47 --- /dev/null +++ b/docs/docs/run_node/guides/node_reference.md @@ -0,0 +1,5 @@ +--- +sidebar_position: 5 +title: Node reference +draft: true +--- \ No newline at end of file diff --git a/docs/docs/run_node/guides/reacting_to_upgrades.md b/docs/docs/run_node/guides/reacting_to_upgrades.md new file mode 100644 index 00000000000..293922e4c0b --- /dev/null +++ b/docs/docs/run_node/guides/reacting_to_upgrades.md @@ -0,0 +1,36 @@ +--- +sidebar_position: 4 +title: Reacting to upgrades +--- + +This is a guide for sequencer nodes to understand how to react to protocol upgrades. To learn about how upgrades work, read the [concept section](../concepts/governance/upgrades.md). + +## Deploying the initial contracts + +Assume that there is an initial deployment, which is a set of contracts as described in the [Deployment section](../concepts/deployments/what_is_deployment.md). + +Once an AZIP garners enough buy-in from the community, sequencers can begin adopting the upgrade. + +## New Rollup contract is deployed to L1 and a proposal is initiated + +To upgrade to a new Rollup instance is to: + +1. Convince the Governance contract to call `Registry.upgrade(_addressOfNewRollup)` + +2. Sequencers move stake to the new Rollup contract to be eligible for any Hypothetical Asset rewards. + +To achieve 1, a new Rollup contract is deployed at an address, and the code for calling `Registry.upgrade(_addressOfNewRollup)` is deployed at a separate address. + +Sequencers of the current canonical rollup, that is the current rollup as pointed to by the Registry, must then call `vote(proposal)` on the Proposals contract. Sequencers can only vote during L2 slots for which they’ve been assigned as the block proposer by the L1 Rollup smart contract. For any given L2 slot, there is only one such sequencer. + +Sequencers vote by updating an environment variable `PROPOSAL_PAYLOAD` in their client software. If enough votes are received by the Proposals contract, any Ethereum account can call `pushProposal(_roundNumber)` where `_roundNumber` can be read from the L1. + +## Voting starts and proposal executed after delay + +Holders who locked their Hypothetical Assets in the Governance contract can vote on proposals. Each vote specifies whether it is in support of the upgrade or not, and the amount of locked Hypothetical Assets the holder wishes to vote. + +If the vote passes, a proposal is moved to an Executable state after some delay. + +## Proposal executed + +Anyone can call `execute(_proposalId)` on the Governance contract which in turn will call the proposal code that was deployed. diff --git a/docs/docs/run_node/guides/run_nodes/_category_.json b/docs/docs/run_node/guides/run_nodes/_category_.json new file mode 100644 index 00000000000..bab7be349b1 --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/_category_.json @@ -0,0 +1,6 @@ +{ + "position": 2, + "collapsible": true, + "collapsed": true, + "label": "Running nodes" +} diff --git a/docs/docs/run_node/guides/run_nodes/how_to_run_prover.md b/docs/docs/run_node/guides/run_nodes/how_to_run_prover.md new file mode 100644 index 00000000000..27e44517a3c --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/how_to_run_prover.md @@ -0,0 +1,8 @@ +--- +sidebar_position: 2 +title: How to Run a Prover Node +--- + +It is recommended to read the concepts before running a node, specifically the [provers and sequencers](../../concepts/provers-and-sequencers/index.md) section. + +As we are in active development, this guide is actively changing. Please refer to [this HackMD page](https://hackmd.io/@aztec-network/epoch-proving-integration-guide#Running-a-Prover-Node) for the latest information. \ No newline at end of file diff --git a/docs/docs/run_node/guides/run_nodes/how_to_run_prover_draft.md b/docs/docs/run_node/guides/run_nodes/how_to_run_prover_draft.md new file mode 100644 index 00000000000..8c1ea44feac --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/how_to_run_prover_draft.md @@ -0,0 +1,96 @@ +--- +sidebar_position: 2 +title: How to run a prover node (draft) +draft: true +--- + +!! We will update and publish this when ready !! + +It is recommended to read the concepts before running a node, specifically the [provers and sequencers](../../concepts/provers-and-sequencers/index.md) section. + +The Aztec client can be run as a Prover Node. In this mode, the client will automatically monitor L1 for unclaimed epochs and propose bids (i.e. EpochProofQuote) for proving them. The prover node watches the L1 to see when a bid they submitted has been accepted by a sequencer, the prover node will then kick off an epoch proving job which performs the following tasks: + +- Downloads the transaction hashes in the epoch and all L1 to L2 messages from L1. +- Downloads the transaction objects with their ClientIVC proofs from a remote node (to be replaced by loading them from the P2P pool). +- Executes transactions in the epoch in order, generating proving jobs for each of them. +- Generates the inputs for each circuit and kicks off individual proving jobs to prover agents, recursively proving until it gets to the root rollup proof. +- Submits the root rollup proof to L1 to advance the proven chain. + +```mermaid +flowchart TD + style prover-node stroke:#333,stroke-width:4px + + prover-node[Prover Node] + proving-job[Proving Job] + tx-provider[Tx Provider] + l1-publisher[L1 Publisher] + l2-block-source[L2 Block Source] + world-state[World State DB] + tx-processor[Tx Processor] + prover-client[Proving Orchestrator] + proving-queue[Proof Broker] + prover-agent[Prover Agent] + bb[Barretenberg] + + prover-node --trigger--> proving-job + proving-job --"process-tx"--> tx-processor --"add-tx"--> prover-client + proving-job --start-batch--> prover-client + proving-job --get-tx-hashes--> l2-block-source + proving-job --"advance-to"--> world-state + proving-job --"get-txs"--> tx-provider + tx-processor --rw--> world-state + world-state --"get-blocks"--> l2-block-source + prover-client --"rw"--> world-state + proving-job --publish-proof--> l1-publisher + prover-client --"push-job"--> proving-queue + %%prover-agent --"pull-job"--> proving-queue + proving-queue <--"pull-jobs"--o prover-agent + subgraph "Prover Agent" + prover-agent --"prove"--> bb + end + + %% p2p-client --> tx-pool --"save-tx"--> tx-db + %% p2p-client --get-blocks--> l2-block-source +``` + +The Aztec client needed to run a prover node is shipped as a [docker image](https://hub.docker.com/r/aztecprotocol/aztec) The image exposes the Aztec CLI as its `ENTRYPOINT`, which includes a `start` command for starting different components. You can download it directly or use the sandbox scripts which will automatically pull the image and add the aztec shell script to your path. + +Once the `aztec` command is available, you can run a prover node via: + +```bash +aztec start --prover-node --archiver +``` + +To run a prover agent, either run `aztec start --prover`, or add the `--prover` flag to the command above to start an in-process prover. + +## Configuration + +The Aztec client is configured via environment variables, the following ones being relevant for the prover node: + +- **ETHEREUM_HOST**: URL to an Ethereum node. +- **L1_CHAIN_ID**: Chain ID for the L1 Ethereum chain. +- **DATA_DIRECTORY**: Local folder where archive and world state data is stored. +- **AZTEC_PORT**: Port where the JSON-RPC APIs will be served. +- **PROVER_PUBLISHER_PRIVATE_KEY**: Private key used for publishing proofs to L1. Ensure it corresponds to an address with ETH to pay for gas. +- **PROVER_AGENT_ENABLED**: Whether to run a prover agent process on the same host running the Prover Node. We recommend setting to `false` and running prover agents on separate hosts. +- **P2P_ENABLED**: Set to `true` so that your node can discover peers, receive tx data and gossip quotes to sequencers. +- **PROVER_COORDINATION_NODE_URL**: Send quotes via http. Only used if `P2P_ENABLED` is `false`. +- **BOOT_NODE_URL**: The URL of the boot node for peer discovery. +- **AZTEC_NODE_URL**: Used by the Prover Node to fetch the L1 contract addresses if they were not manually set via environment variables. + +:::note +For S&P Testnet, we will be providing an Ethereum host, a Boot Node URL and a specific Aztec Image. +::: + +The prover agent, on the other hand, relies on the following environment variables: + +- **PROVER_BROKER_HOST**: URL to the Prover Node that acts as a proving job source. +- **PROVER_AGENT_CONCURRENCY**: Maximum concurrency for this given prover agent. Defaults to `1`. + +Both the prover node and agent also rely on the following: + +- **PROVER_REAL_PROOFS**: Whether to generate actual proofs, as opposed to only simulating the circuit and outputting fake proofs. **Set to `true` for the scope of the S&P Testnet.** +- **LOG_LEVEL**: One of `debug`, `verbose`, `info`, `warn`, or `error`. +- **LOG_JSON**: Set to `true` to output logs in JSON format (unreleased). +- **OTEL_EXPORTER_OTLP_METRICS_ENDPOINT**: Optional URL for pushing telemetry data to a remote OpenTelemetry data collector. + diff --git a/docs/docs/run_node/guides/run_nodes/how_to_run_sequencer_draft.md b/docs/docs/run_node/guides/run_nodes/how_to_run_sequencer_draft.md new file mode 100644 index 00000000000..ff82314a085 --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/how_to_run_sequencer_draft.md @@ -0,0 +1,159 @@ +--- +sidebar_position: 1 +title: How to run a Validator/Sequencer Node (draft) +draft: true +--- + +# Running a Sequencer using Aztec Spartan + +This tool helps to boot an Aztec Sequencer and Prover (S&P) Testnet. + +This script does the following: + +- Checks for the presence of Docker in your machine +- Prompts you for some environment variables +- Outputs a templated docker-compose file with your variables +- Runs the docker compose file + +It should work in most UNIX-based machines. + +## Installation + +To configure a new node, create a new directory and run the install script: + +```bash +mkdir val1 && cd val1 +curl -L sp-testnet.aztec.network | bash +``` + +This will install `aztec-spartan.sh` in the current directory. You can now run it: + +```bash +./aztec-spartan.sh config +``` + +If you don't have Docker installed, the script will do it for you. It will then prompt for any required environment variables and output both a `docker-compose.yml` and an `.env` file. You will also be prompted to choose whether to use a [named volume](https://docs.docker.com/engine/storage/volumes/) (default) or if you want to use a local directory to store the node's data. + +Run `./aztec-spartan.sh` without any command to see all available options, and pass them as flags, i.e. `npx aztec-spartan config -p 8080 -p2p 40400`. If you want to use a different key for p2p peer id, pass it with `-pk `. + +For more options, see the [Node Configuration](#node-configuration) section. + +:::tip +Ensure that each validator instance uses unique ports to avoid conflicts. +::: + +## Running + +You can use `npx aztec-spartan [start/stop/logs/update]` to start, stop, output logs or pull the latest docker images. + +:::note +The above deploy script will connect your node to the p2p network where it will register peers and start receiving messages from other nodes on the network. You will not be in the validator set just yet. + +Once you connect and begin to see gossiped messages such as attestations, proposals etc notify notify a team member and they will add you to the validator set. +::: + +## Node Configuration + +The `aztec-spartan.sh` script will set the following required variables on your behalf. You can ofcourse override the variables set by the script by simply changing the `.env` file directly and re-running `./aztec-spartan.sh` + +| Variable | Description | +| ----- | ----- | +| ETHEREUM_HOST | URL to the Ethereum node your validator will connect to. For as long as we're on private networks, please use the value in `aztec-spartan.sh`| +| BOOTNODE_URL | URL to a bootnode that supplies L1 contract addresses and the ENR of the bootstrap nodes. | +| IMAGE | The docker image to run | + +In addition, the user is prompted to enter 1) an IP Address and a P2P port to be used for the TCP and UDP addresses (defaults to 40400) 2) A port for your node (8080) 3) an Ethereum private key 4) `COINBASE` which is the Ethereum address associated with the private key and 5) a path to a local directory to store node data if you don't opt for a named volume. + +On a first run, the script will generate a p2p private key and store it in `$DATA_DIR/var/lib/aztec/p2p-private-key`. If you wish to change your p2p private key, you can pass it on as a CLI arg using the flag `-pk` or update the `PEER_ID_PRIVATE_KEY` in the env file. + +### Publisher and Archiver + +The Publisher is the main node component that interacts with the Ethereum L1, for read and write operations. It is mainly responsible for block publishing, proof submission and tx management. + +The Archiver's primary functions are data storage and retrieval (i.e. L1->L2 messages), state synchronization and re-org handling. + +|Variable| Description| +|----|-----| +|ETHEREUM_HOST| This is the URL to the L1 node your validator will connect to. For as long as we're on private networks, please use the value in `aztec-spartan.sh`| +|L1_CHAIN_ID | Chain ID of the L1 | +| DATA_DIRECTORY | Optional dir to store archiver and world state data. If omitted will store in memory | +| ARCHIVER_POLLING_INTERVAL_MS | The polling interval in ms for retrieving new L2 blocks and encrypted logs +| SEQ_PUBLISHER_PRIVATE_KEY | This should be the same as your validator private key | +|SEQ_PUBLISH_RETRY_INTERVAL_MS | The interval to wait between publish retries| +| SEQ_VIEM_POLLING_INTERVAL_TIME | The polling interval viem uses in ms | + +### Sequencer Config + +The Sequencer Client is a criticial component that coordinates tx validation, L2 block creation, collecting attestations and block submission (through the Publisher). + +|Variable| Description| +|----|-----| +| VALIDATOR_DISABLED | If this is True, the client won't perform any validator duties. | +|VALIDATOR_ATTESTATIONS_WAIT_TIMEOUT_MS | Wait for attestations timeout. After this, client throws an error and does not propose a block for that slot. | +| VALIDATOR_ATTESTATIONS_POLLING_INTERVAL_MS | If not enough attestations, sleep for this long and check again | +|GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS | To nominate proposals for voting, you must set this variable to the Ethereum address of the `proposal` payload. You must edit this to vote on a governance upgrade.| +| SEQ_ENFORCE_TIME_TABLE | Whether to enforce strict timeliness requirement when building blocks. Refer [here](#sequencer-timeliness-requirements) for more on the timetable | +| SEQ_MAX_TX_PER_BLOCK | Increase this to make larger blocks | +| SEQ_MIN_TX_PER_BLOCK | Increase this to require making larger blocks | +| SEQ_MIN_SECONDS_BETWEEN_BLOCKS | If greater than zero, the sequencer will not propose a block until this much time has passed since the last L2 block was published to L1 | +| SEQ_MAX_SECONDS_BETWEEN_BLOCKS | Sequencer will ignore the minTxPerBlock if this many seconds have passed since the last L2 block.| +| COINBASE | This is the Ethereum address that will receive the validator's share of block rewards. It defaults to your validator address. | +| FEE_RECIPIENT | This is the Aztec address that will receive the validator's share of transaction fees. Also defaults to your validator's address (but on Aztec L2). | + +#### Sequencer Timeliness Requirements + +During testing, it was helpful to constrain some actions of the sequencer based on the time passed into the slot. The time-aware sequencer can be told to do action A only if there's a certain amount of time left in the slot. + +For example, at the beginning of a slot, the sequencer will first sync state, then request txs from peers then attempt to build a block, then collect attestations then publish to L1. You can create constraints of the form "Only attempt to build a block if under 5 seconds have passed in the slot". + +If this is helpful in your testing as well, you can turn it on using the environment variable `SEQ_ENFORCE_TIME_TABLE`. + +Currently the default timetable values are hardcoded in [sequencer.ts](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/sequencer-client/src/sequencer/sequencer.ts#L72). Time checks are enforced in `this.setState()`. + +### P2P Config + +The P2P client coordinates peer-to-peer communication between Nodes. + +| Variable | Description | +| ---- | ------| +| BOOTSTRAP_NODES | A list of bootstrap peer ENRs to connect to. Separated by commas. | +| P2P_TCP_ANNOUNCE_ADDR | Format: `:`| +|P2P_UDP_ANNOUNCE_ADDR |Format: `:`| +| P2P_TCP_LISTEN_ADDR | Format: `:` or can use `0.0.0.0:` to listen on all interfaces| +| P2P_UDP_LISTEN_ADDR |Format: `:` or can use `0.0.0.0:` to listen on all interfaces | +| P2P_QUERY_FOR_IP | Useful in dynamic environments where your IP is not known in advance. Set this to True, and only supply `:TCP_PORT` and `:UDP_PORT` for the `ANNOUNCE_ADDR` variables. If you know your public IP address in advance, set this to False or just provide the full announce addresses. +| P2P_ENABLED | Whether to run the P2P module. Defaults to False, so make sure to set to True | +| P2P_MIN_PEERS | The min number of peers to connect to. | +| P2P_MAX_PEERS | The max number of peers to connect to. | +| P2P_BLOCK_CHECK_INTERVAL_MS | How milliseconds to wait between each check for new L2 blocks. | + +### Prover Config + +Please refer to the [Prover Guide](./how_to_run_prover.md) for info on how to setup your prover node. + +## Governance Upgrades + +During a governance upgrade, we'll announce details on the discord. At some point we'll also write AZIPs (Aztec Improvement Proposals) and post them to either the github or forum to collect feedback. + +We'll deploy the payload to the L1 and share the address of the payload with the sequencers on discord. + +To participate in the governance vote, sequencers must change the variable `GOVERNANCE_PROPOSER_PAYLOAD_ADDRESS` in the Sequencer Client to vote during the L2 slot they've been assigned sequencer duties. + +## Troubleshooting + +:::tip +Please make sure you are in the Discord server and that you have been assigned the role `S&P Participant`. Say gm in the `sequencer-and-prover` channel and turn on notifications for the announcements channel. +::: + +If you encounter any errors or bugs, please try basic troubleshooting steps like restarting your node, checking ports and configs. + +If issue persists, please share on the sequencer-and-prover channel and tag [Amin](discordapp.com/users/65773032211231539). + +Some issues are fairly light, the group and ourselves can help you within 60 minutes. If the issue isn't resolved, please send more information: + +**Error Logs**: Attach any relevant error logs. If possible, note the timestamp when the issue began. +**Error Description**: Briefly describe the issue. Include details like what you were doing when it started, and any unusual behaviors observed. +**Steps to Reproduce (if known)**: If there’s a clear way to reproduce the error, please describe it. +**System Information**: Share details like your system’s operating system, hardware specs, and any other relevant environment information. + +That way we can dedicate more time to troubleshoot and open Github issues if no known fix. \ No newline at end of file diff --git a/docs/docs/run_node/guides/run_nodes/how_to_run_validator_sequencer.md b/docs/docs/run_node/guides/run_nodes/how_to_run_validator_sequencer.md new file mode 100644 index 00000000000..d87d530f9c1 --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/how_to_run_validator_sequencer.md @@ -0,0 +1,10 @@ +--- +sidebar_position: 1 +title: How to run a Validator/Sequencer Node +--- + +It is recommended to read the concepts before running a node, specifically the [provers and sequencers](../../concepts/provers-and-sequencers/index.md) section. + +As we are in active development, this guide is actively changing. Please refer to [this README](https://github.com/AztecProtocol/aztec-packages/blob/master/spartan/releases/README.md) for the latest information. + + diff --git a/docs/docs/run_node/guides/run_nodes/index.md b/docs/docs/run_node/guides/run_nodes/index.md new file mode 100644 index 00000000000..9d4630ebc61 --- /dev/null +++ b/docs/docs/run_node/guides/run_nodes/index.md @@ -0,0 +1,26 @@ +--- +id: index +sidebar_position: 0 +title: Run a Node, Sequencer, or Prover +--- + +## Running Aztec Nodes + +
+ + +

Run Aztec Validator Nodes

+
+ + Participate in the Aztec protocol as a validator (also called a sequencer) that helps form consensus on what goes into a block. Runs on consumer hardware. + +
+ + +

Run Aztec Prover Nodes

+
+ + Participate in the Aztec protocol as a prover node, proving the rollup integrity that is pivotal to the protocol. Runs on hardware fit for data centers. + +
+
\ No newline at end of file diff --git a/docs/docs/run_node/index.md b/docs/docs/run_node/index.md new file mode 100644 index 00000000000..29fdc991272 --- /dev/null +++ b/docs/docs/run_node/index.md @@ -0,0 +1,51 @@ +--- +id: index +sidebar_position: 0 +title: Run a node +--- + +In this section, you can explore how governance works on Aztec, the types of nodes that can be run, and how to contribute to decentralization on the Aztec Testnet. + +## Learn about governance on Aztec + +
+ + +

Governance

+
+ + An introduction to Aztec's governance model + +
+
+ +## Decentralization Components + +
+ + +

Sequencers

+
+ + How sequencers propose and produce blocks + +
+
+ +## Run a node + +
+ + +

Run a validator node (sequencer)

+
+ +
+ + + +

Run a prover node

+
+ +
+
diff --git a/docs/docusaurus.config.js b/docs/docusaurus.config.js index 20918552819..7399dda1006 100644 --- a/docs/docusaurus.config.js +++ b/docs/docusaurus.config.js @@ -134,7 +134,7 @@ const config = { entryPoints: ["../yarn-project/circuit-types/src/interfaces/pxe.ts"], tsconfig: "../yarn-project/circuit-types/tsconfig.json", entryPointStrategy: "expand", - out: "reference/developer_references/aztecjs/pxe", + out: "developers/reference/aztecjs/pxe", readme: "none", sidebar: { categoryLabel: "Private Execution Environment (PXE)", @@ -152,7 +152,7 @@ const config = { ], tsconfig: "../yarn-project/aztec.js/tsconfig.json", entryPointStrategy: "resolve", - out: "reference/developer_references/aztecjs/aztec-js", + out: "developers/reference/aztecjs/aztec-js", readme: "none", sidebar: { categoryLabel: "Aztec.js", @@ -173,7 +173,7 @@ const config = { ], tsconfig: "../yarn-project/accounts/tsconfig.json", entryPointStrategy: "resolve", - out: "reference/developer_references/aztecjs/accounts", + out: "developers/reference/aztecjs/accounts", readme: "none", sidebar: { categoryLabel: "Accounts", @@ -208,19 +208,12 @@ const config = { ], apiKey: "gpH8o2YnqsOEj2jgtIMTULbtHi1kZ2X3", // public search-only api key, safe to commit }, - contextualSearch: true, }, colorMode: { defaultMode: "light", disableSwitch: false, respectPrefersColorScheme: false, }, - // docs: { - // sidebar: { - // hideable: true, - // autoCollapseCategories: false, - // }, - // }, navbar: { logo: { alt: "Aztec Logo", @@ -231,26 +224,32 @@ const config = { items: [ { type: "doc", - docId: "index", + docId: "aztec/index", position: "left", label: "Learn", }, + { type: "docSidebar", - sidebarId: "guidesSidebar", + sidebarId: "buildSidebar", position: "left", - label: "Guides", + label: "Build", }, { type: "docSidebar", - sidebarId: "referenceSidebar", + sidebarId: "nodesSidebar", position: "left", - label: "Reference", + label: "Run a node", + }, + { + to: "/developers/getting_started", + label: "Install Sandbox", + position: "right", }, { type: "dropdown", label: "Resources", - position: "left", + position: "right", items: [ { type: "html", @@ -353,7 +352,7 @@ const config = { }, { label: "Developer Getting Started Guide", - to: "/guides/getting_started", + to: "/developers/getting_started", }, { label: "Aztec.nr", diff --git a/docs/internal_notes/dev_docs/sandbox/components.md b/docs/internal_notes/dev_docs/sandbox/components.md index fb8e6bfa116..f9d407faf88 100644 --- a/docs/internal_notes/dev_docs/sandbox/components.md +++ b/docs/internal_notes/dev_docs/sandbox/components.md @@ -137,7 +137,6 @@ Implementation notes for this milestone: - Can be used as both the spending and decryption key for early development. ### Private Execution Environment (PXE) - ![](https://hackmd.io/_uploads/ryS0sOLyh.png) Implements: diff --git a/docs/netlify.toml b/docs/netlify.toml index 3a0097de71b..5dba9ffe4bb 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -1,22 +1,26 @@ [[redirects]] from = "/guides/smart_contracts/writing_contracts/initializers" - to = "/guides/developer_guides/smart_contracts/writing_contracts/initializers" + to = "/developers/guides/smart_contracts/writing_contracts/initializers" [[redirects]] from = "/reference/aztecjs/accounts" - to = "/reference/developer_references/aztecjs/accounts" + to = "/developers/reference/aztecjs/accounts" [[redirects]] from = "/getting_started" - to = "/guides/getting_started" + to = "/developers/getting_started" [[redirects]] - from = "/tutorials/simple_dapp/*" - to = "/tutorials/codealong/simple_dapp" + from = "/developers/getting_started/main" + to = "/developers/getting_started" + +[[redirects]] + from = "guides/getting_started" + to = "/developers/getting_started" [[redirects]] - from = "/tutorials/simple_dapp" - to = "/tutorials/codealong/simple_dapp" + from = "/tutorials/simple_dapp/*" + to = "developers/tutorials/codealong/js_tutorials/simple_dapp" [[redirects]] from = "/tutorials/contract_tutorials//token_bridge/typescript_glue_code" @@ -64,7 +68,7 @@ [[redirects]] from = "/developers/sandbox/*" - to = "/guides/getting_started" + to = "/developers/getting_started" [[redirects]] from = "/developers/contracts/*" @@ -72,7 +76,7 @@ [[redirects]] from = "/dev_docs/*" - to = "/guides/getting_started" + to = "/developers/getting_started" [[redirects]] from = "/aztec/cryptography/cryptography-roadmap" @@ -136,16 +140,60 @@ [[redirects]] from = "/reference/sandbox_reference/sandbox-reference" - to = "/guides/getting_started" + to = "/developers/getting_started" [[redirects]] from = "/reference/sandbox_reference" - to = "/guides/getting_started" + to = "/developers/getting_started" + +[[redirects]] + from = "/guides/getting_started/*" + to = "/developers/getting_started/*" + +[[redirects]] + from = "/guides/developer_guides/getting_started/quickstart" + to = "/developers/getting_started" + +[[redirects]] + from = "/aztec/concepts_overview" + to = "/aztec" + +[[redirects]] + from = "/aztec/concepts/accounts/authwit" + to = "/aztec/concepts/advanced/authwit" + +[[redirects]] + from = "/aztec/concepts/storage/storage_slots" + to = "/aztec/concepts/advanced/storage/storage_slots" + +[[redirects]] + from = "/aztec/concepts/storage/trees/*" + to = "/aztec/concepts/advanced/storage/indexed_merkle_tree" + +[[redirects]] + from = "/aztec/concepts/storage/partial_notes" + to = "/aztec/concepts/advanced/storage/partial_notes" + +[[redirects]] + from = "/aztec/concepts/circuits/*" + to = "/aztec/concepts/advanced/circuits" + +[[redirects]] + from = "/tutorials/*" + to = "/developers/tutorials/*" + +[[redirects]] + from = "/guides/*" + to = "/developers/guides/*" + +[[redirects]] + from = "/reference/*" + to = "/developers/reference/*" [[redirects]] - from = "/guides/getting_started/quickstart" - to = "/guides/getting_started" + from = "/guides/privacy_considerations" + to = "/developers/reference/considerations/privacy_considerations" [[redirects]] -from = "/guides/developer_guides/getting_started/quickstart" -to = "/guides/developer_guides/getting_started" \ No newline at end of file + from = "/reference/developer_references/limitations" + to = "/developers/reference/considerations/limitations" \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index 0e9563dbfce..98bd39e0a2f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -73,4 +73,4 @@ ] }, "packageManager": "yarn@4.5.2" -} +} \ No newline at end of file diff --git a/docs/scripts/clean.sh b/docs/scripts/clean.sh index 8d27b2091b4..ce1fe639f84 100755 --- a/docs/scripts/clean.sh +++ b/docs/scripts/clean.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash rm -rf 'processed-docs' 'processed-docs-cache' -rm -rf 'docs/reference/developer_references/aztecjs' 'docs/reference/developer_references/smart_contract_reference/aztec-nr' +rm -rf 'docs/developers/reference/aztecjs' 'docs/developers/reference/smart_contract_reference/aztec-nr' docusaurus clear diff --git a/docs/scripts/move_processed.sh b/docs/scripts/move_processed.sh index b841f2e5eb1..23d40065bed 100755 --- a/docs/scripts/move_processed.sh +++ b/docs/scripts/move_processed.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash -echo "label: \"AztecJS\"" > ./docs/reference/developer_references/aztecjs/_category_.yml -mv ./docs/reference/developer_references/aztecjs ./processed-docs/reference/developer_references/aztecjs -mv ./docs/reference/developer_references/smart_contract_reference/aztec-nr ./processed-docs/reference/developer_references/smart_contract_reference/aztec-nr +echo "label: \"AztecJS\"" > ./docs/developers/reference/aztecjs/_category_.yml +mv ./docs/developers/reference/aztecjs ./processed-docs/developers/reference/aztecjs +mv ./docs/developers/reference/smart_contract_reference/aztec-nr ./processed-docs/developers/reference/smart_contract_reference/aztec-nr diff --git a/docs/sidebars.js b/docs/sidebars.js index ae40d1e6a51..7079d256665 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -6,36 +6,16 @@ const path = require("path"); /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ export default { sidebar: [ - { - type: "html", - value: 'Concepts', - className: "sidebar-title", - }, { type: "doc", - id: "aztec/concepts_overview", - label: "Concepts Overview", + id: "aztec/index", + label: "Aztec Overview", }, { type: "category", label: "Concepts", items: [{ type: "autogenerated", dirName: "aztec/concepts" }], }, - { - type: "html", - value: 'Network', - className: "sidebar-title", - }, - { - type: "doc", - id: "aztec/network_overview", - label: "Network Overview", - }, - { - type: "category", - label: "Network Infrastructure", - items: [{ type: "autogenerated", dirName: "aztec/network" }], - }, { type: "html", value: 'Smart Contracts', @@ -62,15 +42,19 @@ export default { { type: "doc", label: "Building in Public", - id: "aztec", + id: "building_in_public", + }, + { + type: "doc", + id: "aztec_connect_sunset", }, ], - guidesSidebar: [ + buildSidebar: [ { type: "doc", - id: "guides/index", - label: "Guides and Tutorials", + id: "developers/index", + label: "Build", }, { type: "html", @@ -80,7 +64,12 @@ export default { { type: "doc", label: "Quickstart", - id: "guides/getting_started" + id: "developers/getting_started" + }, + { + type: "link", + label: "Aztec Starter GitHub repo", + href: "https://github.com/AztecProtocol/aztec-starter", }, { type: "html", @@ -93,16 +82,20 @@ export default { }, { type: "autogenerated", - dirName: "tutorials/codealong", + dirName: "developers/tutorials/codealong", + }, + { + type: "html", + value: '', }, { type: "html", - value: 'Advanced Examples', + value: 'How-to Guides', className: "sidebar-title", }, { type: "autogenerated", - dirName: "tutorials/examples", + dirName: "developers/guides" }, { type: "html", @@ -110,65 +103,59 @@ export default { }, { type: "html", - value: 'How-to Guides', + value: 'References', className: "sidebar-title", }, { type: "autogenerated", - dirName: "guides/developer_guides" + dirName: "developers/reference", }, { type: "html", value: '', }, - ], - - referenceSidebar: [ { type: "doc", - label: "References", - id: "reference/index", + id: "migration_notes", }, + ], + + roadmapSidebar: [ { - type: "html", - value: 'Developer References', - className: "sidebar-title", + type: "autogenerated", + dirName: "aztec/roadmap", }, + ], + + nodesSidebar: [ + { - type: "autogenerated", - dirName: "reference/developer_references", + type: "doc", + id: "run_node/index", }, { type: "html", - value: 'Considerations', + value: 'Concepts', className: "sidebar-title", }, { - type: "doc", - id: "migration_notes", - }, - { - type: "doc", - label: "Privacy Considerations", - id: "guides/privacy_considerations" + type: "autogenerated", + dirName: "run_node/concepts", }, { type: "html", value: '', }, { - type: "doc", - id: "aztec_connect_sunset", + type: "html", + value: 'Guides', + className: "sidebar-title", }, - ], - - roadmapSidebar: [ { type: "autogenerated", - dirName: "aztec/roadmap", + dirName: "run_node/guides", }, ], - ...(process.env.SHOW_PROTOCOL_SPECS ? { protocolSpecSidebar: [ "protocol-specs/intro", diff --git a/docs/src/components/Disclaimers/_wip_disclaimer.mdx b/docs/src/components/Disclaimers/_wip_disclaimer.mdx index 61f31593ea5..131eec88d59 100644 --- a/docs/src/components/Disclaimers/_wip_disclaimer.mdx +++ b/docs/src/components/Disclaimers/_wip_disclaimer.mdx @@ -5,7 +5,7 @@ :::caution Disclaimer We are building Aztec as transparently as we can. The documents published here are living documents. The protocol, sandbox, language, and tools are all subject to change over time. -Please see [here](/reference/developer_references/limitations) for details of known Aztec protocol and Aztec Sandbox limitations. +Please see [here](/developers/reference/considerations/limitations) for details of known Aztec protocol and Aztec Sandbox limitations. If you would like to help us build Aztec: diff --git a/docs/src/preprocess/generate_aztecnr_reference.js b/docs/src/preprocess/generate_aztecnr_reference.js index 7d0a3396a42..3512ec15c36 100644 --- a/docs/src/preprocess/generate_aztecnr_reference.js +++ b/docs/src/preprocess/generate_aztecnr_reference.js @@ -323,7 +323,7 @@ function processFiles(baseDir, outputBaseDir) { let baseDir = path.resolve(__dirname, "../../../noir-projects/aztec-nr"); let outputBaseDir = path.resolve( __dirname, - "../../docs/reference/developer_references/smart_contract_reference/aztec-nr" + "../../docs/developers/reference/smart_contract_reference/aztec-nr" ); console.log(outputBaseDir); processFiles(baseDir, outputBaseDir); diff --git a/docs/static/img/governance.png b/docs/static/img/governance.png new file mode 100644 index 00000000000..991dee3115c Binary files /dev/null and b/docs/static/img/governance.png differ diff --git a/docs/typesense.config.json b/docs/typesense.config.json index f20205e727c..7dccc1f3dc6 100644 --- a/docs/typesense.config.json +++ b/docs/typesense.config.json @@ -1,47 +1,47 @@ { - "index_name": "aztec-docs", - "start_urls": [ - "https://docs.aztec.network/" - ], - "sitemap_urls": [ - "https://docs.aztec.network/sitemap.xml" - ], - "sitemap_alternate_links": true, - "selectors": { - "lvl0": { - "selector": "(//ul[contains(@class,'menu__list')]//a[contains(@class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(@class, 'navbar')]//a[contains(@class, 'navbar__link--active')]/text())[last()]", - "type": "xpath", - "global": true, - "default_value": "Documentation" - }, - "lvl1": "header h1", - "lvl2": "header h2", - "lvl3": "header h3", - "lvl4": "header h4", - "lvl5": "header h5", - "lvl6": "header h6", - "text": "article p, article li, article td:last-child" - }, - "strip_chars": " .,;:#", - "custom_settings": { - "separatorsToIndex": "_", - "attributesForFaceting": [ - "language", - "version", - "type", - "docusaurus_tag" - ], - "attributesToRetrieve": [ - "hierarchy", - "content", - "anchor", - "url", - "url_without_anchor", - "type" - ] + "index_name": "aztec-docs", + "start_urls": [ + "https://docs.aztec.network/" + ], + "sitemap_urls": [ + "https://docs.aztec.network/sitemap.xml" + ], + "sitemap_alternate_links": true, + "selectors": { + "lvl0": { + "selector": "(//ul[contains(@class,'menu__list')]//a[contains(@class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(@class, 'navbar')]//a[contains(@class, 'navbar__link--active')]/text())[last()]", + "type": "xpath", + "global": true, + "default_value": "Documentation" }, - "conversation_id": [ - "833762294" + "lvl1": "header h1", + "lvl2": "header h2", + "lvl3": "header h3", + "lvl4": "header h4", + "lvl5": "header h5", + "lvl6": "header h6", + "text": "article p, article li, article td:last-child" + }, + "strip_chars": " .,;:#", + "custom_settings": { + "separatorsToIndex": "_", + "attributesForFaceting": [ + "language", + "version", + "type", + "docusaurus_tag" ], - "nb_hits": 46250 - } \ No newline at end of file + "attributesToRetrieve": [ + "hierarchy", + "content", + "anchor", + "url", + "url_without_anchor", + "type" + ] + }, + "conversation_id": [ + "833762294" + ], + "nb_hits": 46250 +} \ No newline at end of file diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 98811e1c8b6..cd5345c95d4 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -2,102 +2,57 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; -import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; -import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol"; +import {IRollup, ChainTips} from "@aztec/core/interfaces/IRollup.sol"; import { - IRollup, - ITestRollup, - CheatDepositArgs, + IStaking, + ValidatorInfo, + Exit, + OperatorInfo, + EnumerableSet +} from "@aztec/core/interfaces/IStaking.sol"; +import {IValidatorSelection} from "@aztec/core/interfaces/IValidatorSelection.sol"; + +// We allow the unused imports here as they make it much simpler to import the Rollup later +// solhint-disable no-unused-import +import { + RollupCore, + Config, + IRewardDistributor, + IFeeJuicePortal, + IERC20, + BlockLog, FeeHeader, ManaBaseFeeComponents, - BlockLog, - ChainTips, - RollupStore, - L1GasOracleValues, + SubmitEpochRootProofArgs, L1FeeData, - SubmitEpochRootProofArgs -} from "@aztec/core/interfaces/IRollup.sol"; -import {IVerifier} from "@aztec/core/interfaces/IVerifier.sol"; -import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol"; -import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol"; -import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; -import {MerkleLib} from "@aztec/core/libraries/crypto/MerkleLib.sol"; -import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol"; -import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; -import {Errors} from "@aztec/core/libraries/Errors.sol"; -import { + ValidatorSelectionLib, + StakingLib, + TimeLib, + Slot, + Epoch, + Timestamp, + Errors, + Signature, + DataStructures, ExtRollupLib, - ValidateHeaderArgs, - Header, - SignedEpochProofQuote, - SubmitEpochRootProofInterimValues -} from "@aztec/core/libraries/RollupLibs/ExtRollupLib.sol"; -import {IntRollupLib, EpochProofQuote} from "@aztec/core/libraries/RollupLibs/IntRollupLib.sol"; -import {ProposeArgs, ProposeLib} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol"; -import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol"; -import {Inbox} from "@aztec/core/messagebridge/Inbox.sol"; -import {Outbox} from "@aztec/core/messagebridge/Outbox.sol"; -import {ProofCommitmentEscrow} from "@aztec/core/ProofCommitmentEscrow.sol"; -import {ValidatorSelection} from "@aztec/core/ValidatorSelection.sol"; -import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; -import {MockVerifier} from "@aztec/mock/MockVerifier.sol"; -import {Ownable} from "@oz/access/Ownable.sol"; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; -import {EIP712} from "@oz/utils/cryptography/EIP712.sol"; - -struct Config { - uint256 aztecSlotDuration; - uint256 aztecEpochDuration; - uint256 targetCommitteeSize; - uint256 aztecEpochProofClaimWindowInL2Slots; - uint256 minimumStake; - uint256 slashingQuorum; - uint256 slashingRoundSize; -} + IntRollupLib +} from "./RollupCore.sol"; +// solhint-enable no-unused-import /** * @title Rollup * @author Aztec Labs - * @notice Rollup contract that is concerned about readability and velocity of development - * not giving a damn about gas costs. - * @dev WARNING: This contract is VERY close to the size limit (500B at time of writing). + * @notice A wrapper contract around the RollupCore which provides additional view functions + * which are not needed by the rollup itself to function, but makes it easy to reason + * about the state of the rollup and test it. */ -contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRollup, ITestRollup { - using ProposeLib for ProposeArgs; - using IntRollupLib for uint256; - using IntRollupLib for ManaBaseFeeComponents; - - Slot public constant LIFETIME = Slot.wrap(5); - Slot public constant LAG = Slot.wrap(2); - - // See https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8401-proof-timeliness/proof-timeliness.ipynb - // for justification of CLAIM_DURATION_IN_L2_SLOTS. - uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000; - - // A Cuauhxicalli [kʷaːʍʃiˈkalːi] ("eagle gourd bowl") is a ceremonial Aztec vessel or altar used to hold offerings, - // such as sacrificial hearts, during rituals performed within temples. - address public constant CUAUHXICALLI = address(bytes20("CUAUHXICALLI")); - - address public constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); - bool public immutable IS_FOUNDRY_TEST; - // @note Always true, exists to override to false for testing only - bool public checkBlob = true; - - uint256 public immutable CLAIM_DURATION_IN_L2_SLOTS; - uint256 public immutable L1_BLOCK_AT_GENESIS; - IInbox public immutable INBOX; - IOutbox public immutable OUTBOX; - IProofCommitmentEscrow public immutable PROOF_COMMITMENT_ESCROW; - uint256 public immutable VERSION; - IFeeJuicePortal public immutable FEE_JUICE_PORTAL; - IRewardDistributor public immutable REWARD_DISTRIBUTOR; - IERC20 public immutable ASSET; +contract Rollup is IStaking, IValidatorSelection, IRollup, RollupCore { + using EnumerableSet for EnumerableSet.AddressSet; - RollupStore internal rollupStore; - - // @note Assume that all blocks up to this value (inclusive) are automatically proven. Speeds up bootstrapping. - // Testing only. This should be removed eventually. - uint256 private assumeProvenThroughBlockNumber; + using TimeLib for Timestamp; + using TimeLib for Slot; + using TimeLib for Epoch; + using IntRollupLib for ManaBaseFeeComponents; constructor( IFeeJuicePortal _fpcJuicePortal, @@ -108,207 +63,51 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo address _ares, Config memory _config ) - Ownable(_ares) - ValidatorSelection( + RollupCore( + _fpcJuicePortal, + _rewardDistributor, _stakingAsset, - _config.minimumStake, - _config.slashingQuorum, - _config.slashingRoundSize, - _config.aztecSlotDuration, - _config.aztecEpochDuration, - _config.targetCommitteeSize + _vkTreeRoot, + _protocolContractTreeRoot, + _ares, + _config ) - { - FEE_JUICE_PORTAL = _fpcJuicePortal; - REWARD_DISTRIBUTOR = _rewardDistributor; - ASSET = _fpcJuicePortal.UNDERLYING(); - PROOF_COMMITMENT_ESCROW = new ProofCommitmentEscrow( - ASSET, address(this), _config.aztecSlotDuration, _config.aztecEpochDuration - ); - INBOX = IInbox(address(new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT))); - OUTBOX = IOutbox(address(new Outbox(address(this)))); - VERSION = 1; - L1_BLOCK_AT_GENESIS = block.number; - CLAIM_DURATION_IN_L2_SLOTS = _config.aztecEpochProofClaimWindowInL2Slots; - - IS_FOUNDRY_TEST = VM_ADDRESS.code.length > 0; - - rollupStore.epochProofVerifier = new MockVerifier(); - rollupStore.vkTreeRoot = _vkTreeRoot; - rollupStore.protocolContractTreeRoot = _protocolContractTreeRoot; - - // Genesis block - rollupStore.blocks[0] = BlockLog({ - feeHeader: FeeHeader({ - excessMana: 0, - feeAssetPriceNumerator: 0, - manaUsed: 0, - provingCostPerManaNumerator: 0, - congestionCost: 0 - }), - archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT), - blockHash: bytes32(Constants.GENESIS_BLOCK_HASH), - slotNumber: Slot.wrap(0) - }); - rollupStore.l1GasOracleValues = L1GasOracleValues({ - pre: L1FeeData({baseFee: 1 gwei, blobFee: 1}), - post: L1FeeData({baseFee: block.basefee, blobFee: ExtRollupLib.getBlobBaseFee(VM_ADDRESS)}), - slotOfChange: LIFETIME - }); - } - - function cheat__InitialiseValidatorSet(CheatDepositArgs[] memory _args) - external - override(ITestRollup) - onlyOwner - { - for (uint256 i = 0; i < _args.length; i++) { - _cheat__Deposit(_args[i].attester, _args[i].proposer, _args[i].withdrawer, _args[i].amount); - } - setupEpoch(); + {} + + function getTargetCommitteeSize() external view override(IValidatorSelection) returns (uint256) { + return ValidatorSelectionLib.getStorage().targetCommitteeSize; } - /** - * @notice Prune the pending chain up to the last proven block - * - * @dev Will revert if there is nothing to prune or if the chain is not ready to be pruned - */ - function prune() external override(IRollup) { - require(canPrune(), Errors.Rollup__NothingToPrune()); - _prune(); + function getGenesisTime() external view override(IValidatorSelection) returns (Timestamp) { + return Timestamp.wrap(TimeLib.getStorage().genesisTime); } - /** - * Sets the assumeProvenThroughBlockNumber. Only the contract deployer can set it. - * @param _blockNumber - New value. - */ - function setAssumeProvenThroughBlockNumber(uint256 _blockNumber) - external - override(ITestRollup) - onlyOwner - { - _fakeBlockNumberAsProven(_blockNumber); - assumeProvenThroughBlockNumber = _blockNumber; + function getSlotDuration() external view override(IValidatorSelection) returns (uint256) { + return TimeLib.getStorage().slotDuration; } - /** - * @notice Set the verifier contract - * - * @dev This is only needed for testing, and should be removed - * - * @param _verifier - The new verifier contract - */ - function setEpochVerifier(address _verifier) external override(ITestRollup) onlyOwner { - rollupStore.epochProofVerifier = IVerifier(_verifier); + function getEpochDuration() external view override(IValidatorSelection) returns (uint256) { + return TimeLib.getStorage().epochDuration; } - /** - * @notice Set the vkTreeRoot - * - * @dev This is only needed for testing, and should be removed - * - * @param _vkTreeRoot - The new vkTreeRoot to be used by proofs - */ - function setVkTreeRoot(bytes32 _vkTreeRoot) external override(ITestRollup) onlyOwner { - rollupStore.vkTreeRoot = _vkTreeRoot; + function getSlasher() external view override(IStaking) returns (address) { + return StakingLib.getStorage().slasher; } - /** - * @notice Set the protocolContractTreeRoot - * - * @dev This is only needed for testing, and should be removed - * - * @param _protocolContractTreeRoot - The new protocolContractTreeRoot to be used by proofs - */ - function setProtocolContractTreeRoot(bytes32 _protocolContractTreeRoot) - external - override(ITestRollup) - onlyOwner - { - rollupStore.protocolContractTreeRoot = _protocolContractTreeRoot; + function getStakingAsset() external view override(IStaking) returns (IERC20) { + return StakingLib.getStorage().stakingAsset; } - /** - * @notice Publishes the body and propose the block - * @dev `eth_log_handlers` rely on this function - * - * @param _args - The arguments to propose the block - * @param _signatures - Signatures from the validators - * // TODO(#9101): The below _body should be removed once we can extract blobs. It's only here so the archiver can extract tx effects. - * @param _body - The body of the L2 block - * @param _blobInput - The blob evaluation KZG proof, challenge, and opening required for the precompile. - */ - function proposeAndClaim( - ProposeArgs calldata _args, - Signature[] memory _signatures, - bytes calldata _body, - bytes calldata _blobInput, - SignedEpochProofQuote calldata _quote - ) external override(IRollup) { - propose(_args, _signatures, _body, _blobInput); - claimEpochProofRight(_quote); + function getMinimumStake() external view override(IStaking) returns (uint256) { + return StakingLib.getStorage().minimumStake; } - /** - * @notice Submit a proof for an epoch in the pending chain - * - * @dev Will emit `L2ProofVerified` if the proof is valid - * - * @dev Will throw if: - * - The block number is past the pending chain - * - The last archive root of the header does not match the archive root of parent block - * - The archive root of the header does not match the archive root of the proposed block - * - The proof is invalid - * - * @dev We provide the `_archive` and `_blockHash` even if it could be read from storage itself because it allow for - * better error messages. Without passing it, we would just have a proof verification failure. - * - * @param _args - The arguments to submit the epoch root proof: - * _epochSize - The size of the epoch (to be promoted to a constant) - * _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId) - * _fees - Array of recipient-value pairs with fees to be distributed for the epoch - * _blobPublicInputs - The blob public inputs for the proof - * _aggregationObject - The aggregation object for the proof - * _proof - The proof to verify - */ - function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external override(IRollup) { - if (canPrune()) { - _prune(); - } - - // We want to compute the two epoch values before hand. Could we do partial interim? - // We compute these in here to avoid a lot of pain with linking libraries and passing - // external functions into internal functions as args. - SubmitEpochRootProofInterimValues memory interimValues; - interimValues.previousBlockNumber = rollupStore.tips.provenBlockNumber; - interimValues.endBlockNumber = interimValues.previousBlockNumber + _args.epochSize; - - // @note The _getEpochForBlock is expected to revert if the block is beyond pending. - // If this changes you are gonna get so rekt you won't believe it. - // I mean proving blocks that have been pruned rekt. - interimValues.startEpoch = getEpochForBlock(interimValues.previousBlockNumber + 1); - interimValues.epochToProve = getEpochForBlock(interimValues.endBlockNumber); - - uint256 endBlockNumber = ExtRollupLib.submitEpochRootProof( - rollupStore, - _args, - interimValues, - PROOF_COMMITMENT_ESCROW, - FEE_JUICE_PORTAL, - REWARD_DISTRIBUTOR, - ASSET, - CUAUHXICALLI - ); - emit L2ProofVerified(endBlockNumber, _args.args[6]); + function getExitDelay() external view override(IStaking) returns (Timestamp) { + return StakingLib.getStorage().exitDelay; } - function getProofClaim() - external - view - override(IRollup) - returns (DataStructures.EpochProofClaim memory) - { - return rollupStore.proofClaim; + function getActiveAttesterCount() external view override(IStaking) returns (uint256) { + return StakingLib.getStorage().attesters.length(); } function getTips() external view override(IRollup) returns (ChainTips memory) { @@ -338,6 +137,15 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo ); } + function getProofClaim() + external + view + override(IRollup) + returns (DataStructures.EpochProofClaim memory) + { + return rollupStore.proofClaim; + } + /** * @notice Returns the computed public inputs for the given epoch proof. * @@ -363,40 +171,22 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo } /** - * @notice Check if msg.sender can propose at a given time - * - * @param _ts - The timestamp to check - * @param _archive - The archive to check (should be the latest archive) - * - * @return uint256 - The slot at the given timestamp - * @return uint256 - The block number at the given timestamp + * @notice Get the next epoch that can be claimed + * @dev Will revert if the epoch has already been claimed or if there is no epoch to prove */ - function canProposeAtTime(Timestamp _ts, bytes32 _archive) - external - view - override(IRollup) - returns (Slot, uint256) - { - Slot slot = getSlotAt(_ts); - - // Consider if a prune will hit in this slot - uint256 pendingBlockNumber = - canPruneAtTime(_ts) ? rollupStore.tips.provenBlockNumber : rollupStore.tips.pendingBlockNumber; - - Slot lastSlot = rollupStore.blocks[pendingBlockNumber].slotNumber; - - require(slot > lastSlot, Errors.Rollup__SlotAlreadyInChain(lastSlot, slot)); - - // Make sure that the proposer is up to date and on the right chain (ie no reorgs) - bytes32 tipArchive = rollupStore.blocks[pendingBlockNumber].archive; - require(tipArchive == _archive, Errors.Rollup__InvalidArchive(tipArchive, _archive)); - - Signature[] memory sigs = new Signature[](0); - DataStructures.ExecutionFlags memory flags = - DataStructures.ExecutionFlags({ignoreDA: true, ignoreSignatures: true}); - _validateValidatorSelection(slot, sigs, _archive, flags); - - return (slot, pendingBlockNumber + 1); + function getClaimableEpoch() external view override(IRollup) returns (Epoch) { + Epoch epochToProve = getEpochToProve(); + require( + // If the epoch has been claimed, it cannot be claimed again + rollupStore.proofClaim.epochToProve != epochToProve + // Edge case for if no claim has been made yet. + // We know that the bondProvider is always set, + // Since otherwise the claimEpochProofRight would have reverted, + // because the zero address cannot have deposited funds into escrow. + || rollupStore.proofClaim.bondProvider == address(0), + Errors.Rollup__ProofRightAlreadyClaimed() + ); + return epochToProve; } /** @@ -409,7 +199,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo * @param _signatures - The signatures to validate * @param _digest - The digest to validate * @param _currentTime - The current time - * @param _blobsHashesCommitment - The blobs hash for this block + * @param _blobsHash - The blobs hash for this block * @param _flags - The flags to validate */ function validateHeader( @@ -417,7 +207,7 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo Signature[] memory _signatures, bytes32 _digest, Timestamp _currentTime, - bytes32 _blobsHashesCommitment, + bytes32 _blobsHash, DataStructures.ExecutionFlags memory _flags ) external view override(IRollup) { _validateHeader( @@ -426,13 +216,13 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo _digest, _currentTime, getManaBaseFeeAt(_currentTime, true), - _blobsHashesCommitment, + _blobsHash, _flags ); } /** - * @notice Validate blob transactions against given inputs + * @notice Validate blob transactions against given inputs. * @dev Only exists here for gas estimation. */ function validateBlobs(bytes calldata _blobsInput) @@ -445,316 +235,281 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo } /** - * @notice Get the next epoch that can be claimed - * @dev Will revert if the epoch has already been claimed or if there is no epoch to prove + * @notice Get the current archive root + * + * @return bytes32 - The current archive root */ - function getClaimableEpoch() external view override(IRollup) returns (Epoch) { - Epoch epochToProve = getEpochToProve(); + function archive() external view override(IRollup) returns (bytes32) { + return rollupStore.blocks[rollupStore.tips.pendingBlockNumber].archive; + } + + function getProvenBlockNumber() external view override(IRollup) returns (uint256) { + return rollupStore.tips.provenBlockNumber; + } + + function getPendingBlockNumber() external view override(IRollup) returns (uint256) { + return rollupStore.tips.pendingBlockNumber; + } + + function getBlock(uint256 _blockNumber) external view override(IRollup) returns (BlockLog memory) { require( - // If the epoch has been claimed, it cannot be claimed again - rollupStore.proofClaim.epochToProve != epochToProve - // Edge case for if no claim has been made yet. - // We know that the bondProvider is always set, - // Since otherwise the claimEpochProofRight would have reverted, - // because the zero address cannot have deposited funds into escrow. - || rollupStore.proofClaim.bondProvider == address(0), - Errors.Rollup__ProofRightAlreadyClaimed() + _blockNumber <= rollupStore.tips.pendingBlockNumber, + Errors.Rollup__InvalidBlockNumber(rollupStore.tips.pendingBlockNumber, _blockNumber) ); - return epochToProve; + return rollupStore.blocks[_blockNumber]; } - function claimEpochProofRight(SignedEpochProofQuote calldata _quote) public override(IRollup) { - validateEpochProofRightClaimAtTime(Timestamp.wrap(block.timestamp), _quote); + function getBlobPublicInputsHash(uint256 _blockNumber) + external + view + override(IRollup) + returns (bytes32) + { + return rollupStore.blobPublicInputsHashes[_blockNumber]; + } - Slot currentSlot = getCurrentSlot(); - Epoch epochToProve = getEpochToProve(); + function getProposerForAttester(address _attester) + external + view + override(IStaking) + returns (address) + { + return StakingLib.getStorage().info[_attester].proposer; + } - // We don't currently unstake, - // but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652. - // Blocked on submitting epoch proofs to this contract. - PROOF_COMMITMENT_ESCROW.stakeBond(_quote.quote.prover, _quote.quote.bondAmount); - - rollupStore.proofClaim = DataStructures.EpochProofClaim({ - epochToProve: epochToProve, - basisPointFee: _quote.quote.basisPointFee, - bondAmount: _quote.quote.bondAmount, - bondProvider: _quote.quote.prover, - proposerClaimant: msg.sender - }); - - emit ProofRightClaimed( - epochToProve, _quote.quote.prover, msg.sender, _quote.quote.bondAmount, currentSlot - ); + function getAttesterAtIndex(uint256 _index) external view override(IStaking) returns (address) { + return StakingLib.getStorage().attesters.at(_index); } - /** - * @notice Publishes the body and propose the block - * @dev `eth_log_handlers` rely on this function - * - * @param _args - The arguments to propose the block - * @param _signatures - Signatures from the validators - * // TODO(#9101): The below _body should be removed once we can extract blobs. It's only here so the archiver can extract tx effects. - * @param - The body of the L2 block - * @param _blobInput - The blob evaluation KZG proof, challenge, and opening required for the precompile. - */ - function propose( - ProposeArgs calldata _args, - Signature[] memory _signatures, - // TODO(#9101): Extract blobs from beacon chain => remove below body input - bytes calldata, - bytes calldata _blobInput - ) public override(IRollup) { - if (canPrune()) { - _prune(); - } - updateL1GasFeeOracle(); - - // Since an invalid blob hash here would fail the consensus checks of - // the header, the `blobInput` is implicitly accepted by consensus as well. - (bytes32[] memory blobHashes, bytes32 blobsHashesCommitment, bytes32 blobPublicInputsHash) = - ExtRollupLib.validateBlobs(_blobInput, checkBlob); - - // Decode and validate header - Header memory header = ExtRollupLib.decodeHeader(_args.header); - - setupEpoch(); - ManaBaseFeeComponents memory components = - getManaBaseFeeComponentsAt(Timestamp.wrap(block.timestamp), true); - uint256 manaBaseFee = components.summedBaseFee(); - _validateHeader({ - _header: header, - _signatures: _signatures, - _digest: _args.digest(), - _currentTime: Timestamp.wrap(block.timestamp), - _manaBaseFee: manaBaseFee, - _blobsHashesCommitment: blobsHashesCommitment, - _flags: DataStructures.ExecutionFlags({ignoreDA: false, ignoreSignatures: false}) - }); - - uint256 blockNumber = ++rollupStore.tips.pendingBlockNumber; - - { - rollupStore.blocks[blockNumber] = _toBlockLog(_args, blockNumber, components.congestionCost); - } - - rollupStore.blobPublicInputsHashes[blockNumber] = blobPublicInputsHash; - - // @note The block number here will always be >=1 as the genesis block is at 0 - { - bytes32 inHash = INBOX.consume(blockNumber); - require( - header.contentCommitment.inHash == inHash, - Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash) - ); - } - - // TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim - // Min size = smallest path of the rollup tree + 1 - (uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs); - OUTBOX.insert(blockNumber, header.contentCommitment.outHash, min + 1); - - emit L2BlockProposed(blockNumber, _args.archive, blobHashes); - - // Automatically flag the block as proven if we have cheated and set assumeProvenThroughBlockNumber. - if (blockNumber <= assumeProvenThroughBlockNumber) { - _fakeBlockNumberAsProven(blockNumber); - - bool isFeeCanonical = address(this) == FEE_JUICE_PORTAL.canonicalRollup(); - bool isRewardDistributorCanonical = address(this) == REWARD_DISTRIBUTOR.canonicalRollup(); - - if (isFeeCanonical && header.globalVariables.coinbase != address(0) && header.totalFees > 0) { - // @note This will currently fail if there are insufficient funds in the bridge - // which WILL happen for the old version after an upgrade where the bridge follow. - // Consider allowing a failure. See #7938. - FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees); - } - if (isRewardDistributorCanonical && header.globalVariables.coinbase != address(0)) { - REWARD_DISTRIBUTOR.claim(header.globalVariables.coinbase); - } - - emit L2ProofVerified(blockNumber, "CHEAT"); - } + function getProposerAtIndex(uint256 _index) external view override(IStaking) returns (address) { + return StakingLib.getStorage().info[StakingLib.getStorage().attesters.at(_index)].proposer; } - /** - * @notice Updates the l1 gas fee oracle - * @dev This function is called by the `propose` function - */ - function updateL1GasFeeOracle() public override(IRollup) { - Slot slot = getCurrentSlot(); - // The slot where we find a new queued value acceptable - Slot acceptableSlot = rollupStore.l1GasOracleValues.slotOfChange + (LIFETIME - LAG); + function getInfo(address _attester) + external + view + override(IStaking) + returns (ValidatorInfo memory) + { + return StakingLib.getStorage().info[_attester]; + } - if (slot < acceptableSlot) { - return; - } + function getExit(address _attester) external view override(IStaking) returns (Exit memory) { + return StakingLib.getStorage().exits[_attester]; + } - rollupStore.l1GasOracleValues.pre = rollupStore.l1GasOracleValues.post; - rollupStore.l1GasOracleValues.post = - L1FeeData({baseFee: block.basefee, blobFee: ExtRollupLib.getBlobBaseFee(VM_ADDRESS)}); - rollupStore.l1GasOracleValues.slotOfChange = slot + LAG; + function getOperatorAtIndex(uint256 _index) + external + view + override(IStaking) + returns (OperatorInfo memory) + { + address attester = StakingLib.getStorage().attesters.at(_index); + return + OperatorInfo({proposer: StakingLib.getStorage().info[attester].proposer, attester: attester}); } /** - * @notice Gets the fee asset price as fee_asset / eth with 1e9 precision + * @notice Get the validator set for a given epoch + * + * @dev Consider removing this to replace with a `size` and individual getter. + * + * @param _epoch The epoch number to get the validator set for * - * @return The fee asset price + * @return The validator set for the given epoch */ - function getFeeAssetPrice() public view override(IRollup) returns (uint256) { - return IntRollupLib.feeAssetPriceModifier( - rollupStore.blocks[rollupStore.tips.pendingBlockNumber].feeHeader.feeAssetPriceNumerator - ); + function getEpochCommittee(Epoch _epoch) + external + view + override(IValidatorSelection) + returns (address[] memory) + { + return ValidatorSelectionLib.getStorage().epochs[_epoch].committee; } - function getL1FeesAt(Timestamp _timestamp) - public + /** + * @notice Get the validator set for the current epoch + * @return The validator set for the current epoch + */ + function getCurrentEpochCommittee() + external view - override(IRollup) - returns (L1FeeData memory) + override(IValidatorSelection) + returns (address[] memory) { - return getSlotAt(_timestamp) < rollupStore.l1GasOracleValues.slotOfChange - ? rollupStore.l1GasOracleValues.pre - : rollupStore.l1GasOracleValues.post; + return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getCurrentEpoch()); } /** - * @notice Gets the mana base fee + * @notice Get the committee for a given timestamp * - * @param _inFeeAsset - Whether to return the fee in the fee asset or ETH + * @param _ts - The timestamp to get the committee for * - * @return The mana base fee + * @return The committee for the given timestamp */ - function getManaBaseFeeAt(Timestamp _timestamp, bool _inFeeAsset) - public + function getCommitteeAt(Timestamp _ts) + external view - override(IRollup) - returns (uint256) + override(IValidatorSelection) + returns (address[] memory) { - return getManaBaseFeeComponentsAt(_timestamp, _inFeeAsset).summedBaseFee(); + return ValidatorSelectionLib.getCommitteeAt(StakingLib.getStorage(), getEpochAt(_ts)); } /** - * @notice Gets the mana base fee components - * For more context, consult: - * https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8757-fees/design.md + * @notice Get the sample seed for a given timestamp * - * @dev TODO #10004 - As part of the refactor, will likely get rid of this function or make it private - * keeping it public for now makes it simpler to test. + * @param _ts - The timestamp to get the sample seed for * - * @param _inFeeAsset - Whether to return the fee in the fee asset or ETH - * - * @return The mana base fee components + * @return The sample seed for the given timestamp */ - function getManaBaseFeeComponentsAt(Timestamp _timestamp, bool _inFeeAsset) - public + function getSampleSeedAt(Timestamp _ts) + external view - override(ITestRollup) - returns (ManaBaseFeeComponents memory) + override(IValidatorSelection) + returns (uint256) { - // If we can prune, we use the proven block, otherwise the pending block - uint256 blockOfInterest = canPruneAtTime(_timestamp) - ? rollupStore.tips.provenBlockNumber - : rollupStore.tips.pendingBlockNumber; - - return ExtRollupLib.getManaBaseFeeComponentsAt( - rollupStore.blocks[blockOfInterest].feeHeader, - getL1FeesAt(_timestamp), - _inFeeAsset ? getFeeAssetPrice() : 1e9, - TimeLib.getStorage().epochDuration - ); + return ValidatorSelectionLib.getSampleSeed(getEpochAt(_ts)); } - function quoteToDigest(EpochProofQuote memory _quote) - public - view - override(IRollup) - returns (bytes32) - { - return _hashTypedDataV4(IntRollupLib.computeQuoteHash(_quote)); + /** + * @notice Get the sample seed for the current epoch + * + * @return The sample seed for the current epoch + */ + function getCurrentSampleSeed() external view override(IValidatorSelection) returns (uint256) { + return ValidatorSelectionLib.getSampleSeed(getCurrentEpoch()); } - function validateEpochProofRightClaimAtTime(Timestamp _ts, SignedEpochProofQuote calldata _quote) - public - view - override(IRollup) - { - Slot currentSlot = getSlotAt(_ts); - address currentProposer = getProposerAt(_ts); - Epoch epochToProve = getEpochToProve(); - uint256 posInEpoch = TimeLib.positionInEpoch(currentSlot); - bytes32 digest = quoteToDigest(_quote.quote); - - ExtRollupLib.validateEpochProofRightClaimAtTime( - currentSlot, - currentProposer, - epochToProve, - posInEpoch, - _quote, - digest, - rollupStore.proofClaim, - CLAIM_DURATION_IN_L2_SLOTS, - PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST, - PROOF_COMMITMENT_ESCROW - ); + /** + * @notice Get the attester set + * + * @dev Consider removing this to replace with a `size` and individual getter. + * + * @return The validator set + */ + function getAttesters() external view override(IValidatorSelection) returns (address[] memory) { + return StakingLib.getStorage().attesters.values(); } /** - * @notice Get the current archive root + * @notice Get the current slot number * - * @return bytes32 - The current archive root + * @return The current slot number */ - function archive() public view override(IRollup) returns (bytes32) { - return rollupStore.blocks[rollupStore.tips.pendingBlockNumber].archive; + function getCurrentSlot() external view override(IValidatorSelection) returns (Slot) { + return Timestamp.wrap(block.timestamp).slotFromTimestamp(); } - function getProvenBlockNumber() public view override(IRollup) returns (uint256) { - return rollupStore.tips.provenBlockNumber; + /** + * @notice Get the timestamp for a given slot + * + * @param _slotNumber - The slot number to get the timestamp for + * + * @return The timestamp for the given slot + */ + function getTimestampForSlot(Slot _slotNumber) + external + view + override(IValidatorSelection) + returns (Timestamp) + { + return _slotNumber.toTimestamp(); } - function getPendingBlockNumber() public view override(IRollup) returns (uint256) { - return rollupStore.tips.pendingBlockNumber; + /** + * @notice Get the proposer for the current slot + * + * @dev Calls `getCurrentProposer(uint256)` with the current timestamp + * + * @return The address of the proposer + */ + function getCurrentProposer() external view override(IValidatorSelection) returns (address) { + return getProposerAt(Timestamp.wrap(block.timestamp)); } - function getBlock(uint256 _blockNumber) public view override(IRollup) returns (BlockLog memory) { - require( - _blockNumber <= rollupStore.tips.pendingBlockNumber, - Errors.Rollup__InvalidBlockNumber(rollupStore.tips.pendingBlockNumber, _blockNumber) - ); - return rollupStore.blocks[_blockNumber]; + /** + * @notice Computes the slot at a specific time + * + * @param _ts - The timestamp to compute the slot for + * + * @return The computed slot + */ + function getSlotAt(Timestamp _ts) external view override(IValidatorSelection) returns (Slot) { + return _ts.slotFromTimestamp(); } - function getBlobPublicInputsHash(uint256 _blockNumber) - public + /** + * @notice Computes the epoch at a specific slot + * + * @param _slotNumber - The slot number to compute the epoch for + * + * @return The computed epoch + */ + function getEpochAtSlot(Slot _slotNumber) + external view - override(IRollup) - returns (bytes32) + override(IValidatorSelection) + returns (Epoch) { - return rollupStore.blobPublicInputsHashes[_blockNumber]; + return _slotNumber.epochFromSlot(); } - function getEpochForBlock(uint256 _blockNumber) public view override(IRollup) returns (Epoch) { - require( - _blockNumber <= rollupStore.tips.pendingBlockNumber, - Errors.Rollup__InvalidBlockNumber(rollupStore.tips.pendingBlockNumber, _blockNumber) + /** + * @notice Check if msg.sender can propose at a given time + * + * @param _ts - The timestamp to check + * @param _archive - The archive to check (should be the latest archive) + * + * @return uint256 - The slot at the given timestamp + * @return uint256 - The block number at the given timestamp + */ + function canProposeAtTime(Timestamp _ts, bytes32 _archive) + external + view + override(IRollup) + returns (Slot, uint256) + { + Slot slot = _ts.slotFromTimestamp(); + + // Consider if a prune will hit in this slot + uint256 pendingBlockNumber = + canPruneAtTime(_ts) ? rollupStore.tips.provenBlockNumber : rollupStore.tips.pendingBlockNumber; + + Slot lastSlot = rollupStore.blocks[pendingBlockNumber].slotNumber; + + require(slot > lastSlot, Errors.Rollup__SlotAlreadyInChain(lastSlot, slot)); + + // Make sure that the proposer is up to date and on the right chain (ie no reorgs) + bytes32 tipArchive = rollupStore.blocks[pendingBlockNumber].archive; + require(tipArchive == _archive, Errors.Rollup__InvalidArchive(tipArchive, _archive)); + + Signature[] memory sigs = new Signature[](0); + DataStructures.ExecutionFlags memory flags = + DataStructures.ExecutionFlags({ignoreDA: true, ignoreSignatures: true}); + + Epoch currentEpoch = slot.epochFromSlot(); + ValidatorSelectionLib.validateValidatorSelection( + StakingLib.getStorage(), slot, currentEpoch, sigs, _archive, flags ); - return getEpochAt(getTimestampForSlot(rollupStore.blocks[_blockNumber].slotNumber)); + + return (slot, pendingBlockNumber + 1); } /** - * @notice Get the epoch that should be proven + * @notice Gets the mana base fee * - * @dev This is the epoch that should be proven. It does so by getting the epoch of the block - * following the last proven block. If there is no such block (i.e. the pending chain is - * the same as the proven chain), then revert. + * @param _inFeeAsset - Whether to return the fee in the fee asset or ETH * - * @return uint256 - The epoch to prove + * @return The mana base fee */ - function getEpochToProve() public view override(IRollup) returns (Epoch) { - require( - rollupStore.tips.provenBlockNumber != rollupStore.tips.pendingBlockNumber, - Errors.Rollup__NoEpochToProve() - ); - return getEpochForBlock(rollupStore.tips.provenBlockNumber + 1); + function getManaBaseFeeAt(Timestamp _timestamp, bool _inFeeAsset) + public + view + override(IRollup) + returns (uint256) + { + return getManaBaseFeeComponentsAt(_timestamp, _inFeeAsset).summedBaseFee(); } /** @@ -770,185 +525,50 @@ contract Rollup is EIP712("Aztec Rollup", "1"), Ownable, ValidatorSelection, IRo : bytes32(0); } - function canPrune() public view override(IRollup) returns (bool) { - return canPruneAtTime(Timestamp.wrap(block.timestamp)); - } - - function canPruneAtTime(Timestamp _ts) public view override(IRollup) returns (bool) { - if ( - rollupStore.tips.pendingBlockNumber == rollupStore.tips.provenBlockNumber - || rollupStore.tips.pendingBlockNumber <= assumeProvenThroughBlockNumber - ) { - return false; - } - - Slot currentSlot = getSlotAt(_ts); - Epoch oldestPendingEpoch = getEpochForBlock(rollupStore.tips.provenBlockNumber + 1); - Slot startSlotOfPendingEpoch = TimeLib.toSlots(oldestPendingEpoch); - - // suppose epoch 1 is proven, epoch 2 is pending, epoch 3 is the current epoch. - // we prune the pending chain back to the end of epoch 1 if: - // - the proof claim phase of epoch 3 has ended without a claim to prove epoch 2 (or proof of epoch 2) - // - we reach epoch 4 without a proof of epoch 2 (regardless of whether a proof claim was submitted) - bool inClaimPhase = currentSlot - < startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(1)) - + Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS); - - bool claimExists = currentSlot < startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(2)) - && rollupStore.proofClaim.epochToProve == oldestPendingEpoch - && rollupStore.proofClaim.proposerClaimant != address(0); - - if (inClaimPhase || claimExists) { - // If we are in the claim phase, do not prune - return false; - } - return true; - } - - function _prune() internal { - // TODO #8656 - delete rollupStore.proofClaim; - - uint256 pending = rollupStore.tips.pendingBlockNumber; - - // @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven. - // We can do because any new block proposed will overwrite a previous block in the block log, - // so no values should "survive". - // People must therefore read the chain using the pendingTip as a boundary. - rollupStore.tips.pendingBlockNumber = rollupStore.tips.provenBlockNumber; - - emit PrunedPending(rollupStore.tips.provenBlockNumber, pending); + /** + * @notice Computes the epoch at a specific time + * + * @param _ts - The timestamp to compute the epoch for + * + * @return The computed epoch + */ + function getEpochAt(Timestamp _ts) public view override(IValidatorSelection) returns (Epoch) { + return _ts.epochFromTimestamp(); } /** - * @notice Validates the header for submission - * - * @param _header - The proposed block header - * @param _signatures - The signatures for the attestations - * @param _digest - The digest that signatures signed - * @param _currentTime - The time of execution - * @param _blobsHashesCommitment - The blobs hash for this block - * @dev - This value is provided to allow for simple simulation of future - * @param _flags - Flags specific to the execution, whether certain checks should be skipped + * @notice Get the current epoch number + * + * @return The current epoch number */ - function _validateHeader( - Header memory _header, - Signature[] memory _signatures, - bytes32 _digest, - Timestamp _currentTime, - uint256 _manaBaseFee, - bytes32 _blobsHashesCommitment, - DataStructures.ExecutionFlags memory _flags - ) internal view { - uint256 pendingBlockNumber = canPruneAtTime(_currentTime) - ? rollupStore.tips.provenBlockNumber - : rollupStore.tips.pendingBlockNumber; - - ExtRollupLib.validateHeaderForSubmissionBase( - ValidateHeaderArgs({ - header: _header, - currentTime: _currentTime, - manaBaseFee: _manaBaseFee, - blobsHashesCommitment: _blobsHashesCommitment, - pendingBlockNumber: pendingBlockNumber, - flags: _flags, - version: VERSION, - feeJuicePortal: FEE_JUICE_PORTAL, - getTimestampForSlot: this.getTimestampForSlot - }), - rollupStore.blocks - ); - _validateHeaderForSubmissionSequencerSelection( - Slot.wrap(_header.globalVariables.slotNumber), _signatures, _digest, _currentTime, _flags - ); + function getCurrentEpoch() public view override(IValidatorSelection) returns (Epoch) { + return Timestamp.wrap(block.timestamp).epochFromTimestamp(); } /** - * @notice Validate a header for submission to the pending chain (sequencer selection checks) + * @notice Get the proposer for the slot at a specific timestamp * - * These validation checks are directly related to ValidatorSelection. - * Note that while these checks are strict, they can be relaxed with some changes to - * message boxes. + * @dev This function is very useful for off-chain usage, as it easily allow a client to + * determine who will be the proposer at the NEXT ethereum block. + * Should not be trusted when moving beyond the current epoch, since changes to the + * validator set might not be reflected when we actually reach that epoch (more changes + * might have happened). * - * Each of the following validation checks must pass, otherwise an error is thrown and we revert. - * - The slot MUST be the current slot - * This might be relaxed for allow consensus set to better handle short-term bursts of L1 congestion - * - The slot MUST be in the current epoch + * @dev The proposer is selected from the validator set of the current epoch. * - * @param _slot - The slot of the header to validate - * @param _signatures - The signatures to validate - * @param _digest - The digest that signatures sign over + * @dev Should only be access on-chain if epoch is setup, otherwise very expensive. + * + * @dev A return value of address(0) means that the proposer is "open" and can be anyone. + * + * @dev If the current epoch is the first epoch, returns address(0) + * If the current epoch is setup, we will return the proposer for the current slot + * If the current epoch is not setup, we will perform a sample as if it was (gas heavy) + * + * @return The address of the proposer */ - function _validateHeaderForSubmissionSequencerSelection( - Slot _slot, - Signature[] memory _signatures, - bytes32 _digest, - Timestamp _currentTime, - DataStructures.ExecutionFlags memory _flags - ) internal view { - // Ensure that the slot proposed is NOT in the future - Slot currentSlot = getSlotAt(_currentTime); - require(_slot == currentSlot, Errors.HeaderLib__InvalidSlotNumber(currentSlot, _slot)); - - // @note We are currently enforcing that the slot is in the current epoch - // If this is not the case, there could potentially be a weird reorg - // of an entire epoch if no-one from the new epoch committee have seen - // those blocks or behaves as if they did not. - - Epoch epochNumber = getEpochAt(getTimestampForSlot(_slot)); - Epoch currentEpoch = getEpochAt(_currentTime); - require(epochNumber == currentEpoch, Errors.Rollup__InvalidEpoch(currentEpoch, epochNumber)); - - _validateValidatorSelection(_slot, _signatures, _digest, _flags); - } - - // Helper to avoid stack too deep - function _toBlockLog(ProposeArgs calldata _args, uint256 _blockNumber, uint256 _congestionCost) - internal - view - returns (BlockLog memory) - { - FeeHeader memory parentFeeHeader = rollupStore.blocks[_blockNumber - 1].feeHeader; - return BlockLog({ - archive: _args.archive, - blockHash: _args.blockHash, - slotNumber: Slot.wrap(uint256(bytes32(_args.header[0x0194:0x01b4]))), - feeHeader: FeeHeader({ - excessMana: IntRollupLib.computeExcessMana(parentFeeHeader), - feeAssetPriceNumerator: parentFeeHeader.feeAssetPriceNumerator.clampedAdd( - _args.oracleInput.feeAssetPriceModifier - ), - manaUsed: uint256(bytes32(_args.header[0x0268:0x0288])), - provingCostPerManaNumerator: parentFeeHeader.provingCostPerManaNumerator.clampedAdd( - _args.oracleInput.provingCostModifier - ), - congestionCost: _congestionCost - }) - }); - } - - function _fakeBlockNumberAsProven(uint256 _blockNumber) private { - if ( - _blockNumber > rollupStore.tips.provenBlockNumber - && _blockNumber <= rollupStore.tips.pendingBlockNumber - ) { - rollupStore.tips.provenBlockNumber = _blockNumber; - - // If this results on a new epoch, create a fake claim for it - // Otherwise nextEpochToProve will report an old epoch - Epoch epoch = getEpochForBlock(_blockNumber); - if ( - Epoch.unwrap(epoch) == 0 - || Epoch.unwrap(epoch) > Epoch.unwrap(rollupStore.proofClaim.epochToProve) - ) { - rollupStore.proofClaim = DataStructures.EpochProofClaim({ - epochToProve: epoch, - basisPointFee: 0, - bondAmount: 0, - bondProvider: address(0), - proposerClaimant: msg.sender - }); - } - } + function getProposerAt(Timestamp _ts) public view override(IValidatorSelection) returns (address) { + Slot slot = _ts.slotFromTimestamp(); + Epoch epochNumber = slot.epochFromSlot(); + return ValidatorSelectionLib.getProposerAt(StakingLib.getStorage(), slot, epochNumber); } } diff --git a/l1-contracts/src/core/RollupCore.sol b/l1-contracts/src/core/RollupCore.sol new file mode 100644 index 00000000000..34a5d6d0100 --- /dev/null +++ b/l1-contracts/src/core/RollupCore.sol @@ -0,0 +1,782 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.27; + +import {IFeeJuicePortal} from "@aztec/core/interfaces/IFeeJuicePortal.sol"; +import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol"; +import { + IRollupCore, + ITestRollup, + CheatDepositArgs, + FeeHeader, + ManaBaseFeeComponents, + BlockLog, + RollupStore, + L1GasOracleValues, + L1FeeData, + SubmitEpochRootProofArgs +} from "@aztec/core/interfaces/IRollup.sol"; +import {IStakingCore} from "@aztec/core/interfaces/IStaking.sol"; +import {IValidatorSelectionCore} from "@aztec/core/interfaces/IValidatorSelection.sol"; +import {IVerifier} from "@aztec/core/interfaces/IVerifier.sol"; +import {IInbox} from "@aztec/core/interfaces/messagebridge/IInbox.sol"; +import {IOutbox} from "@aztec/core/interfaces/messagebridge/IOutbox.sol"; +import {Constants} from "@aztec/core/libraries/ConstantsGen.sol"; +import {MerkleLib} from "@aztec/core/libraries/crypto/MerkleLib.sol"; +import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol"; +import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; +import {Errors} from "@aztec/core/libraries/Errors.sol"; +import { + ExtRollupLib, + ValidateHeaderArgs, + Header, + SignedEpochProofQuote, + SubmitEpochRootProofInterimValues +} from "@aztec/core/libraries/RollupLibs/ExtRollupLib.sol"; +import {IntRollupLib, EpochProofQuote} from "@aztec/core/libraries/RollupLibs/IntRollupLib.sol"; +import {ProposeArgs, ProposeLib} from "@aztec/core/libraries/RollupLibs/ProposeLib.sol"; +import {StakingLib} from "@aztec/core/libraries/staking/StakingLib.sol"; +import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol"; +import {ValidatorSelectionLib} from + "@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol"; +import {Inbox} from "@aztec/core/messagebridge/Inbox.sol"; +import {Outbox} from "@aztec/core/messagebridge/Outbox.sol"; +import {ProofCommitmentEscrow} from "@aztec/core/ProofCommitmentEscrow.sol"; +import {Slasher} from "@aztec/core/staking/Slasher.sol"; +import {IRewardDistributor} from "@aztec/governance/interfaces/IRewardDistributor.sol"; +import {MockVerifier} from "@aztec/mock/MockVerifier.sol"; +import {Ownable} from "@oz/access/Ownable.sol"; +import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {EIP712} from "@oz/utils/cryptography/EIP712.sol"; + +struct Config { + uint256 aztecSlotDuration; + uint256 aztecEpochDuration; + uint256 targetCommitteeSize; + uint256 aztecEpochProofClaimWindowInL2Slots; + uint256 minimumStake; + uint256 slashingQuorum; + uint256 slashingRoundSize; +} + +/** + * @title Rollup + * @author Aztec Labs + * @notice Rollup contract that is concerned about readability and velocity of development + * not giving a damn about gas costs. + * @dev WARNING: This contract is VERY close to the size limit (500B at time of writing). + */ +contract RollupCore is + EIP712("Aztec Rollup", "1"), + Ownable, + IStakingCore, + IValidatorSelectionCore, + IRollupCore, + ITestRollup +{ + using ProposeLib for ProposeArgs; + using IntRollupLib for uint256; + using IntRollupLib for ManaBaseFeeComponents; + + using TimeLib for Timestamp; + using TimeLib for Slot; + using TimeLib for Epoch; + + Slot public constant LIFETIME = Slot.wrap(5); + Slot public constant LAG = Slot.wrap(2); + + // See https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8401-proof-timeliness/proof-timeliness.ipynb + // for justification of CLAIM_DURATION_IN_L2_SLOTS. + uint256 public constant PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST = 1000; + + // A Cuauhxicalli [kʷaːʍʃiˈkalːi] ("eagle gourd bowl") is a ceremonial Aztec vessel or altar used to hold offerings, + // such as sacrificial hearts, during rituals performed within temples. + address public constant CUAUHXICALLI = address(bytes20("CUAUHXICALLI")); + + address public constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code")))); + bool public immutable IS_FOUNDRY_TEST; + + uint256 public immutable CLAIM_DURATION_IN_L2_SLOTS; + uint256 public immutable L1_BLOCK_AT_GENESIS; + IInbox public immutable INBOX; + IOutbox public immutable OUTBOX; + IProofCommitmentEscrow public immutable PROOF_COMMITMENT_ESCROW; + uint256 public immutable VERSION; + IFeeJuicePortal public immutable FEE_JUICE_PORTAL; + IRewardDistributor public immutable REWARD_DISTRIBUTOR; + IERC20 public immutable ASSET; + + // To push checkblock into its own slot so we don't have the trouble of being in the middle of a slot + uint256 private gap = 0; + + // @note Always true, exists to override to false for testing only + bool public checkBlob = true; + + RollupStore internal rollupStore; + + // @note Assume that all blocks up to this value (inclusive) are automatically proven. Speeds up bootstrapping. + // Testing only. This should be removed eventually. + uint256 private assumeProvenThroughBlockNumber; + + constructor( + IFeeJuicePortal _fpcJuicePortal, + IRewardDistributor _rewardDistributor, + IERC20 _stakingAsset, + bytes32 _vkTreeRoot, + bytes32 _protocolContractTreeRoot, + address _ares, + Config memory _config + ) Ownable(_ares) { + TimeLib.initialize(block.timestamp, _config.aztecSlotDuration, _config.aztecEpochDuration); + + Timestamp exitDelay = Timestamp.wrap(60 * 60 * 24); + Slasher slasher = new Slasher(_config.slashingQuorum, _config.slashingRoundSize); + StakingLib.initialize(_stakingAsset, _config.minimumStake, exitDelay, address(slasher)); + ValidatorSelectionLib.initialize(_config.targetCommitteeSize); + + FEE_JUICE_PORTAL = _fpcJuicePortal; + REWARD_DISTRIBUTOR = _rewardDistributor; + ASSET = _fpcJuicePortal.UNDERLYING(); + PROOF_COMMITMENT_ESCROW = new ProofCommitmentEscrow( + ASSET, address(this), _config.aztecSlotDuration, _config.aztecEpochDuration + ); + INBOX = IInbox(address(new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT))); + OUTBOX = IOutbox(address(new Outbox(address(this)))); + VERSION = 1; + L1_BLOCK_AT_GENESIS = block.number; + CLAIM_DURATION_IN_L2_SLOTS = _config.aztecEpochProofClaimWindowInL2Slots; + + IS_FOUNDRY_TEST = VM_ADDRESS.code.length > 0; + + rollupStore.epochProofVerifier = new MockVerifier(); + rollupStore.vkTreeRoot = _vkTreeRoot; + rollupStore.protocolContractTreeRoot = _protocolContractTreeRoot; + + // Genesis block + rollupStore.blocks[0] = BlockLog({ + feeHeader: FeeHeader({ + excessMana: 0, + feeAssetPriceNumerator: 0, + manaUsed: 0, + provingCostPerManaNumerator: 0, + congestionCost: 0 + }), + archive: bytes32(Constants.GENESIS_ARCHIVE_ROOT), + blockHash: bytes32(Constants.GENESIS_BLOCK_HASH), + slotNumber: Slot.wrap(0) + }); + rollupStore.l1GasOracleValues = L1GasOracleValues({ + pre: L1FeeData({baseFee: 1 gwei, blobFee: 1}), + post: L1FeeData({baseFee: block.basefee, blobFee: ExtRollupLib.getBlobBaseFee(VM_ADDRESS)}), + slotOfChange: LIFETIME + }); + } + + function deposit(address _attester, address _proposer, address _withdrawer, uint256 _amount) + external + override(IStakingCore) + { + setupEpoch(); + StakingLib.deposit(_attester, _proposer, _withdrawer, _amount); + } + + function initiateWithdraw(address _attester, address _recipient) + external + override(IStakingCore) + returns (bool) + { + // @note The attester might be chosen for the epoch, so the delay must be long enough + // to allow for that. + setupEpoch(); + return StakingLib.initiateWithdraw(_attester, _recipient); + } + + function finaliseWithdraw(address _attester) external override(IStakingCore) { + StakingLib.finaliseWithdraw(_attester); + } + + function slash(address _attester, uint256 _amount) external override(IStakingCore) { + StakingLib.slash(_attester, _amount); + } + + function cheat__InitialiseValidatorSet(CheatDepositArgs[] memory _args) + external + override(ITestRollup) + onlyOwner + { + for (uint256 i = 0; i < _args.length; i++) { + StakingLib.deposit(_args[i].attester, _args[i].proposer, _args[i].withdrawer, _args[i].amount); + } + setupEpoch(); + } + + /** + * @notice Prune the pending chain up to the last proven block + * + * @dev Will revert if there is nothing to prune or if the chain is not ready to be pruned + */ + function prune() external override(IRollupCore) { + require(canPrune(), Errors.Rollup__NothingToPrune()); + _prune(); + } + + /** + * Sets the assumeProvenThroughBlockNumber. Only the contract deployer can set it. + * @param _blockNumber - New value. + */ + function setAssumeProvenThroughBlockNumber(uint256 _blockNumber) + external + override(ITestRollup) + onlyOwner + { + _fakeBlockNumberAsProven(_blockNumber); + assumeProvenThroughBlockNumber = _blockNumber; + } + + /** + * @notice Set the verifier contract + * + * @dev This is only needed for testing, and should be removed + * + * @param _verifier - The new verifier contract + */ + function setEpochVerifier(address _verifier) external override(ITestRollup) onlyOwner { + rollupStore.epochProofVerifier = IVerifier(_verifier); + } + + /** + * @notice Set the vkTreeRoot + * + * @dev This is only needed for testing, and should be removed + * + * @param _vkTreeRoot - The new vkTreeRoot to be used by proofs + */ + function setVkTreeRoot(bytes32 _vkTreeRoot) external override(ITestRollup) onlyOwner { + rollupStore.vkTreeRoot = _vkTreeRoot; + } + + /** + * @notice Set the protocolContractTreeRoot + * + * @dev This is only needed for testing, and should be removed + * + * @param _protocolContractTreeRoot - The new protocolContractTreeRoot to be used by proofs + */ + function setProtocolContractTreeRoot(bytes32 _protocolContractTreeRoot) + external + override(ITestRollup) + onlyOwner + { + rollupStore.protocolContractTreeRoot = _protocolContractTreeRoot; + } + + /** + * @notice Publishes the body and propose the block + * @dev `eth_log_handlers` rely on this function + * + * @param _args - The arguments to propose the block + * @param _signatures - Signatures from the validators + * // TODO(#9101): The below _body should be removed once we can extract blobs. It's only here so the archiver can extract tx effects. + * @param _body - The body of the L2 block + * @param _blobInput - The blob evaluation KZG proof, challenge, and opening required for the precompile. + */ + function proposeAndClaim( + ProposeArgs calldata _args, + Signature[] memory _signatures, + bytes calldata _body, + bytes calldata _blobInput, + SignedEpochProofQuote calldata _quote + ) external override(IRollupCore) { + propose(_args, _signatures, _body, _blobInput); + claimEpochProofRight(_quote); + } + + /** + * @notice Submit a proof for an epoch in the pending chain + * + * @dev Will emit `L2ProofVerified` if the proof is valid + * + * @dev Will throw if: + * - The block number is past the pending chain + * - The last archive root of the header does not match the archive root of parent block + * - The archive root of the header does not match the archive root of the proposed block + * - The proof is invalid + * + * @dev We provide the `_archive` and `_blockHash` even if it could be read from storage itself because it allow for + * better error messages. Without passing it, we would just have a proof verification failure. + * + * @param _args - The arguments to submit the epoch root proof: + * _epochSize - The size of the epoch (to be promoted to a constant) + * _args - Array of public inputs to the proof (previousArchive, endArchive, previousBlockHash, endBlockHash, endTimestamp, outHash, proverId) + * _fees - Array of recipient-value pairs with fees to be distributed for the epoch + * _blobPublicInputs - The blob public inputs for the proof + * _aggregationObject - The aggregation object for the proof + * _proof - The proof to verify + */ + function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) + external + override(IRollupCore) + { + if (canPrune()) { + _prune(); + } + + // We want to compute the two epoch values before hand. Could we do partial interim? + // We compute these in here to avoid a lot of pain with linking libraries and passing + // external functions into internal functions as args. + SubmitEpochRootProofInterimValues memory interimValues; + interimValues.previousBlockNumber = rollupStore.tips.provenBlockNumber; + interimValues.endBlockNumber = interimValues.previousBlockNumber + _args.epochSize; + + // @note The _getEpochForBlock is expected to revert if the block is beyond pending. + // If this changes you are gonna get so rekt you won't believe it. + // I mean proving blocks that have been pruned rekt. + interimValues.startEpoch = getEpochForBlock(interimValues.previousBlockNumber + 1); + interimValues.epochToProve = getEpochForBlock(interimValues.endBlockNumber); + + uint256 endBlockNumber = ExtRollupLib.submitEpochRootProof( + rollupStore, + _args, + interimValues, + PROOF_COMMITMENT_ESCROW, + FEE_JUICE_PORTAL, + REWARD_DISTRIBUTOR, + ASSET, + CUAUHXICALLI + ); + emit L2ProofVerified(endBlockNumber, _args.args[6]); + } + + function setupEpoch() public override(IValidatorSelectionCore) { + ValidatorSelectionLib.setupEpoch(StakingLib.getStorage()); + } + + function claimEpochProofRight(SignedEpochProofQuote calldata _quote) public override(IRollupCore) { + validateEpochProofRightClaimAtTime(Timestamp.wrap(block.timestamp), _quote); + + Slot currentSlot = Timestamp.wrap(block.timestamp).slotFromTimestamp(); + Epoch epochToProve = getEpochToProve(); + + // We don't currently unstake, + // but we will as part of https://github.com/AztecProtocol/aztec-packages/issues/8652. + // Blocked on submitting epoch proofs to this contract. + PROOF_COMMITMENT_ESCROW.stakeBond(_quote.quote.prover, _quote.quote.bondAmount); + + rollupStore.proofClaim = DataStructures.EpochProofClaim({ + epochToProve: epochToProve, + basisPointFee: _quote.quote.basisPointFee, + bondAmount: _quote.quote.bondAmount, + bondProvider: _quote.quote.prover, + proposerClaimant: msg.sender + }); + + emit ProofRightClaimed( + epochToProve, _quote.quote.prover, msg.sender, _quote.quote.bondAmount, currentSlot + ); + } + + /** + * @notice Publishes the body and propose the block + * @dev `eth_log_handlers` rely on this function + * + * @param _args - The arguments to propose the block + * @param _signatures - Signatures from the validators + * // TODO(#9101): The below _body should be removed once we can extract blobs. It's only here so the archiver can extract tx effects. + * @param - The body of the L2 block + * @param _blobInput - The blob evaluation KZG proof, challenge, and opening required for the precompile. + */ + function propose( + ProposeArgs calldata _args, + Signature[] memory _signatures, + // TODO(#9101): Extract blobs from beacon chain => remove below body input + bytes calldata, + bytes calldata _blobInput + ) public override(IRollupCore) { + if (canPrune()) { + _prune(); + } + updateL1GasFeeOracle(); + + // Since an invalid blob hash here would fail the consensus checks of + // the header, the `blobInput` is implicitly accepted by consensus as well. + (bytes32[] memory blobHashes, bytes32 blobsHashesCommitment, bytes32 blobPublicInputsHash) = + ExtRollupLib.validateBlobs(_blobInput, checkBlob); + + // Decode and validate header + Header memory header = ExtRollupLib.decodeHeader(_args.header); + + setupEpoch(); + ManaBaseFeeComponents memory components = + getManaBaseFeeComponentsAt(Timestamp.wrap(block.timestamp), true); + uint256 manaBaseFee = components.summedBaseFee(); + _validateHeader({ + _header: header, + _signatures: _signatures, + _digest: _args.digest(), + _currentTime: Timestamp.wrap(block.timestamp), + _manaBaseFee: manaBaseFee, + _blobsHashesCommitment: blobsHashesCommitment, + _flags: DataStructures.ExecutionFlags({ignoreDA: false, ignoreSignatures: false}) + }); + + uint256 blockNumber = ++rollupStore.tips.pendingBlockNumber; + + { + rollupStore.blocks[blockNumber] = _toBlockLog(_args, blockNumber, components.congestionCost); + } + + rollupStore.blobPublicInputsHashes[blockNumber] = blobPublicInputsHash; + + // @note The block number here will always be >=1 as the genesis block is at 0 + { + bytes32 inHash = INBOX.consume(blockNumber); + require( + header.contentCommitment.inHash == inHash, + Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash) + ); + } + + // TODO(#7218): Revert to fixed height tree for outbox, currently just providing min as interim + // Min size = smallest path of the rollup tree + 1 + (uint256 min,) = MerkleLib.computeMinMaxPathLength(header.contentCommitment.numTxs); + OUTBOX.insert(blockNumber, header.contentCommitment.outHash, min + 1); + + emit L2BlockProposed(blockNumber, _args.archive, blobHashes); + + // Automatically flag the block as proven if we have cheated and set assumeProvenThroughBlockNumber. + if (blockNumber <= assumeProvenThroughBlockNumber) { + _fakeBlockNumberAsProven(blockNumber); + + bool isFeeCanonical = address(this) == FEE_JUICE_PORTAL.canonicalRollup(); + bool isRewardDistributorCanonical = address(this) == REWARD_DISTRIBUTOR.canonicalRollup(); + + if (isFeeCanonical && header.globalVariables.coinbase != address(0) && header.totalFees > 0) { + // @note This will currently fail if there are insufficient funds in the bridge + // which WILL happen for the old version after an upgrade where the bridge follow. + // Consider allowing a failure. See #7938. + FEE_JUICE_PORTAL.distributeFees(header.globalVariables.coinbase, header.totalFees); + } + if (isRewardDistributorCanonical && header.globalVariables.coinbase != address(0)) { + REWARD_DISTRIBUTOR.claim(header.globalVariables.coinbase); + } + + emit L2ProofVerified(blockNumber, "CHEAT"); + } + } + + /** + * @notice Updates the l1 gas fee oracle + * @dev This function is called by the `propose` function + */ + function updateL1GasFeeOracle() public override(IRollupCore) { + Slot slot = Timestamp.wrap(block.timestamp).slotFromTimestamp(); + // The slot where we find a new queued value acceptable + Slot acceptableSlot = rollupStore.l1GasOracleValues.slotOfChange + (LIFETIME - LAG); + + if (slot < acceptableSlot) { + return; + } + + rollupStore.l1GasOracleValues.pre = rollupStore.l1GasOracleValues.post; + rollupStore.l1GasOracleValues.post = + L1FeeData({baseFee: block.basefee, blobFee: ExtRollupLib.getBlobBaseFee(VM_ADDRESS)}); + rollupStore.l1GasOracleValues.slotOfChange = slot + LAG; + } + + /** + * @notice Gets the fee asset price as fee_asset / eth with 1e9 precision + * + * @return The fee asset price + */ + function getFeeAssetPrice() public view override(IRollupCore) returns (uint256) { + return IntRollupLib.feeAssetPriceModifier( + rollupStore.blocks[rollupStore.tips.pendingBlockNumber].feeHeader.feeAssetPriceNumerator + ); + } + + function getL1FeesAt(Timestamp _timestamp) + public + view + override(IRollupCore) + returns (L1FeeData memory) + { + return _timestamp.slotFromTimestamp() < rollupStore.l1GasOracleValues.slotOfChange + ? rollupStore.l1GasOracleValues.pre + : rollupStore.l1GasOracleValues.post; + } + + /** + * @notice Gets the mana base fee components + * For more context, consult: + * https://github.com/AztecProtocol/engineering-designs/blob/main/in-progress/8757-fees/design.md + * + * @dev TODO #10004 - As part of the refactor, will likely get rid of this function or make it private + * keeping it public for now makes it simpler to test. + * + * @param _inFeeAsset - Whether to return the fee in the fee asset or ETH + * + * @return The mana base fee components + */ + function getManaBaseFeeComponentsAt(Timestamp _timestamp, bool _inFeeAsset) + public + view + override(ITestRollup) + returns (ManaBaseFeeComponents memory) + { + // If we can prune, we use the proven block, otherwise the pending block + uint256 blockOfInterest = canPruneAtTime(_timestamp) + ? rollupStore.tips.provenBlockNumber + : rollupStore.tips.pendingBlockNumber; + + return ExtRollupLib.getManaBaseFeeComponentsAt( + rollupStore.blocks[blockOfInterest].feeHeader, + getL1FeesAt(_timestamp), + _inFeeAsset ? getFeeAssetPrice() : 1e9, + TimeLib.getStorage().epochDuration + ); + } + + function quoteToDigest(EpochProofQuote memory _quote) + public + view + override(IRollupCore) + returns (bytes32) + { + return _hashTypedDataV4(IntRollupLib.computeQuoteHash(_quote)); + } + + function validateEpochProofRightClaimAtTime(Timestamp _ts, SignedEpochProofQuote calldata _quote) + public + view + override(IRollupCore) + { + Slot currentSlot = _ts.slotFromTimestamp(); + address currentProposer = ValidatorSelectionLib.getProposerAt( + StakingLib.getStorage(), currentSlot, currentSlot.epochFromSlot() + ); + Epoch epochToProve = getEpochToProve(); + uint256 posInEpoch = TimeLib.positionInEpoch(currentSlot); + bytes32 digest = quoteToDigest(_quote.quote); + + ExtRollupLib.validateEpochProofRightClaimAtTime( + currentSlot, + currentProposer, + epochToProve, + posInEpoch, + _quote, + digest, + rollupStore.proofClaim, + CLAIM_DURATION_IN_L2_SLOTS, + PROOF_COMMITMENT_MIN_BOND_AMOUNT_IN_TST, + PROOF_COMMITMENT_ESCROW + ); + } + + function getEpochForBlock(uint256 _blockNumber) public view override(IRollupCore) returns (Epoch) { + require( + _blockNumber <= rollupStore.tips.pendingBlockNumber, + Errors.Rollup__InvalidBlockNumber(rollupStore.tips.pendingBlockNumber, _blockNumber) + ); + return rollupStore.blocks[_blockNumber].slotNumber.epochFromSlot(); + } + + /** + * @notice Get the epoch that should be proven + * + * @dev This is the epoch that should be proven. It does so by getting the epoch of the block + * following the last proven block. If there is no such block (i.e. the pending chain is + * the same as the proven chain), then revert. + * + * @return uint256 - The epoch to prove + */ + function getEpochToProve() public view override(IRollupCore) returns (Epoch) { + require( + rollupStore.tips.provenBlockNumber != rollupStore.tips.pendingBlockNumber, + Errors.Rollup__NoEpochToProve() + ); + return getEpochForBlock(rollupStore.tips.provenBlockNumber + 1); + } + + function canPrune() public view override(IRollupCore) returns (bool) { + return canPruneAtTime(Timestamp.wrap(block.timestamp)); + } + + function canPruneAtTime(Timestamp _ts) public view override(IRollupCore) returns (bool) { + if ( + rollupStore.tips.pendingBlockNumber == rollupStore.tips.provenBlockNumber + || rollupStore.tips.pendingBlockNumber <= assumeProvenThroughBlockNumber + ) { + return false; + } + + Slot currentSlot = _ts.slotFromTimestamp(); + Epoch oldestPendingEpoch = getEpochForBlock(rollupStore.tips.provenBlockNumber + 1); + Slot startSlotOfPendingEpoch = oldestPendingEpoch.toSlots(); + + // suppose epoch 1 is proven, epoch 2 is pending, epoch 3 is the current epoch. + // we prune the pending chain back to the end of epoch 1 if: + // - the proof claim phase of epoch 3 has ended without a claim to prove epoch 2 (or proof of epoch 2) + // - we reach epoch 4 without a proof of epoch 2 (regardless of whether a proof claim was submitted) + bool inClaimPhase = currentSlot + < startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(1)) + + Slot.wrap(CLAIM_DURATION_IN_L2_SLOTS); + + bool claimExists = currentSlot < startSlotOfPendingEpoch + TimeLib.toSlots(Epoch.wrap(2)) + && rollupStore.proofClaim.epochToProve == oldestPendingEpoch + && rollupStore.proofClaim.proposerClaimant != address(0); + + if (inClaimPhase || claimExists) { + // If we are in the claim phase, do not prune + return false; + } + return true; + } + + function _prune() internal { + // TODO #8656 + delete rollupStore.proofClaim; + + uint256 pending = rollupStore.tips.pendingBlockNumber; + + // @note We are not deleting the blocks, but we are "winding back" the pendingTip to the last block that was proven. + // We can do because any new block proposed will overwrite a previous block in the block log, + // so no values should "survive". + // People must therefore read the chain using the pendingTip as a boundary. + rollupStore.tips.pendingBlockNumber = rollupStore.tips.provenBlockNumber; + + emit PrunedPending(rollupStore.tips.provenBlockNumber, pending); + } + + /** + * @notice Validates the header for submission + * + * @param _header - The proposed block header + * @param _signatures - The signatures for the attestations + * @param _digest - The digest that signatures signed + * @param _currentTime - The time of execution + * @param _blobsHashesCommitment - The blobs hash for this block + * @dev - This value is provided to allow for simple simulation of future + * @param _flags - Flags specific to the execution, whether certain checks should be skipped + */ + function _validateHeader( + Header memory _header, + Signature[] memory _signatures, + bytes32 _digest, + Timestamp _currentTime, + uint256 _manaBaseFee, + bytes32 _blobsHashesCommitment, + DataStructures.ExecutionFlags memory _flags + ) internal view { + uint256 pendingBlockNumber = canPruneAtTime(_currentTime) + ? rollupStore.tips.provenBlockNumber + : rollupStore.tips.pendingBlockNumber; + + ExtRollupLib.validateHeaderForSubmissionBase( + ValidateHeaderArgs({ + header: _header, + currentTime: _currentTime, + manaBaseFee: _manaBaseFee, + blobsHashesCommitment: _blobsHashesCommitment, + pendingBlockNumber: pendingBlockNumber, + flags: _flags, + version: VERSION, + feeJuicePortal: FEE_JUICE_PORTAL + }), + rollupStore.blocks + ); + _validateHeaderForSubmissionSequencerSelection( + Slot.wrap(_header.globalVariables.slotNumber), _signatures, _digest, _currentTime, _flags + ); + } + + /** + * @notice Validate a header for submission to the pending chain (sequencer selection checks) + * + * These validation checks are directly related to sequencer selection. + * Note that while these checks are strict, they can be relaxed with some changes to + * message boxes. + * + * Each of the following validation checks must pass, otherwise an error is thrown and we revert. + * - The slot MUST be the current slot + * This might be relaxed for allow consensus set to better handle short-term bursts of L1 congestion + * - The slot MUST be in the current epoch + * + * @param _slot - The slot of the header to validate + * @param _signatures - The signatures to validate + * @param _digest - The digest that signatures sign over + */ + function _validateHeaderForSubmissionSequencerSelection( + Slot _slot, + Signature[] memory _signatures, + bytes32 _digest, + Timestamp _currentTime, + DataStructures.ExecutionFlags memory _flags + ) internal view { + // Ensure that the slot proposed is NOT in the future + Slot currentSlot = _currentTime.slotFromTimestamp(); + require(_slot == currentSlot, Errors.HeaderLib__InvalidSlotNumber(currentSlot, _slot)); + + // @note We are currently enforcing that the slot is in the current epoch + // If this is not the case, there could potentially be a weird reorg + // of an entire epoch if no-one from the new epoch committee have seen + // those blocks or behaves as if they did not. + + Epoch epochNumber = _slot.epochFromSlot(); + Epoch currentEpoch = _currentTime.epochFromTimestamp(); + require(epochNumber == currentEpoch, Errors.Rollup__InvalidEpoch(currentEpoch, epochNumber)); + + ValidatorSelectionLib.validateValidatorSelection( + StakingLib.getStorage(), _slot, epochNumber, _signatures, _digest, _flags + ); + } + + // Helper to avoid stack too deep + function _toBlockLog(ProposeArgs calldata _args, uint256 _blockNumber, uint256 _congestionCost) + internal + view + returns (BlockLog memory) + { + FeeHeader memory parentFeeHeader = rollupStore.blocks[_blockNumber - 1].feeHeader; + return BlockLog({ + archive: _args.archive, + blockHash: _args.blockHash, + slotNumber: Slot.wrap(uint256(bytes32(_args.header[0x0194:0x01b4]))), + feeHeader: FeeHeader({ + excessMana: IntRollupLib.computeExcessMana(parentFeeHeader), + feeAssetPriceNumerator: parentFeeHeader.feeAssetPriceNumerator.clampedAdd( + _args.oracleInput.feeAssetPriceModifier + ), + manaUsed: uint256(bytes32(_args.header[0x0268:0x0288])), + provingCostPerManaNumerator: parentFeeHeader.provingCostPerManaNumerator.clampedAdd( + _args.oracleInput.provingCostModifier + ), + congestionCost: _congestionCost + }) + }); + } + + function _fakeBlockNumberAsProven(uint256 _blockNumber) private { + if ( + _blockNumber > rollupStore.tips.provenBlockNumber + && _blockNumber <= rollupStore.tips.pendingBlockNumber + ) { + rollupStore.tips.provenBlockNumber = _blockNumber; + + // If this results on a new epoch, create a fake claim for it + // Otherwise nextEpochToProve will report an old epoch + Epoch epoch = getEpochForBlock(_blockNumber); + if ( + Epoch.unwrap(epoch) == 0 + || Epoch.unwrap(epoch) > Epoch.unwrap(rollupStore.proofClaim.epochToProve) + ) { + rollupStore.proofClaim = DataStructures.EpochProofClaim({ + epochToProve: epoch, + basisPointFee: 0, + bondAmount: 0, + bondProvider: address(0), + proposerClaimant: msg.sender + }); + } + } + } +} diff --git a/l1-contracts/src/core/ValidatorSelection.sol b/l1-contracts/src/core/ValidatorSelection.sol deleted file mode 100644 index 9dc6b172652..00000000000 --- a/l1-contracts/src/core/ValidatorSelection.sol +++ /dev/null @@ -1,453 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.27; - -import {IStaking, ValidatorInfo, Exit, OperatorInfo} from "@aztec/core/interfaces/IStaking.sol"; -import { - IValidatorSelection, - EpochData, - ValidatorSelectionStorage -} from "@aztec/core/interfaces/IValidatorSelection.sol"; -import {Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol"; -import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; -import {Errors} from "@aztec/core/libraries/Errors.sol"; -import {StakingLib} from "@aztec/core/libraries/staking/StakingLib.sol"; -import { - Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib -} from "@aztec/core/libraries/TimeLib.sol"; -import {ValidatorSelectionLib} from - "@aztec/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol"; -import {Slasher} from "@aztec/core/staking/Slasher.sol"; -import {IERC20} from "@oz/token/ERC20/IERC20.sol"; -import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol"; - -/** - * @title Validator Selection - * - * @dev Validator Selection has one thing in mind, he provide a reference of the LOGIC going on for the spartan selection. - * It is a reference implementation, it is not optimized for gas. - * - */ -contract ValidatorSelection is IValidatorSelection, IStaking { - using EnumerableSet for EnumerableSet.AddressSet; - - using SlotLib for Slot; - using EpochLib for Epoch; - using TimeLib for Timestamp; - using TimeLib for Slot; - using TimeLib for Epoch; - - // The target number of validators in a committee - // @todo #8021 - uint256 public immutable TARGET_COMMITTEE_SIZE; - - ValidatorSelectionStorage private validatorSelectionStore; - - constructor( - IERC20 _stakingAsset, - uint256 _minimumStake, - uint256 _slashingQuorum, - uint256 _roundSize, - uint256 _slotDuration, - uint256 _epochDuration, - uint256 _targetCommitteeSize - ) { - TARGET_COMMITTEE_SIZE = _targetCommitteeSize; - - TimeLib.initialize(block.timestamp, _slotDuration, _epochDuration); - - Timestamp exitDelay = Timestamp.wrap(60 * 60 * 24); - Slasher slasher = new Slasher(_slashingQuorum, _roundSize); - StakingLib.initialize(_stakingAsset, _minimumStake, exitDelay, address(slasher)); - } - - function deposit(address _attester, address _proposer, address _withdrawer, uint256 _amount) - external - override(IStaking) - { - setupEpoch(); - require( - _attester != address(0) && _proposer != address(0), - Errors.ValidatorSelection__InvalidDeposit(_attester, _proposer) - ); - StakingLib.deposit(_attester, _proposer, _withdrawer, _amount); - } - - function initiateWithdraw(address _attester, address _recipient) - external - override(IStaking) - returns (bool) - { - // @note The attester might be chosen for the epoch, so the delay must be long enough - // to allow for that. - setupEpoch(); - return StakingLib.initiateWithdraw(_attester, _recipient); - } - - function finaliseWithdraw(address _attester) external override(IStaking) { - StakingLib.finaliseWithdraw(_attester); - } - - function slash(address _attester, uint256 _amount) external override(IStaking) { - StakingLib.slash(_attester, _amount); - } - - function getGenesisTime() external view override(IValidatorSelection) returns (Timestamp) { - return Timestamp.wrap(TimeLib.getStorage().genesisTime); - } - - function getSlotDuration() external view override(IValidatorSelection) returns (uint256) { - return TimeLib.getStorage().slotDuration; - } - - function getEpochDuration() external view override(IValidatorSelection) returns (uint256) { - return TimeLib.getStorage().epochDuration; - } - - function getSlasher() external view override(IStaking) returns (address) { - return StakingLib.getStorage().slasher; - } - - function getStakingAsset() external view override(IStaking) returns (IERC20) { - return StakingLib.getStorage().stakingAsset; - } - - function getMinimumStake() external view override(IStaking) returns (uint256) { - return StakingLib.getStorage().minimumStake; - } - - function getExitDelay() external view override(IStaking) returns (Timestamp) { - return StakingLib.getStorage().exitDelay; - } - - function getActiveAttesterCount() external view override(IStaking) returns (uint256) { - return StakingLib.getStorage().attesters.length(); - } - - function getProposerForAttester(address _attester) - external - view - override(IStaking) - returns (address) - { - return StakingLib.getStorage().info[_attester].proposer; - } - - function getAttesterAtIndex(uint256 _index) external view override(IStaking) returns (address) { - return StakingLib.getStorage().attesters.at(_index); - } - - function getProposerAtIndex(uint256 _index) external view override(IStaking) returns (address) { - return StakingLib.getStorage().info[StakingLib.getStorage().attesters.at(_index)].proposer; - } - - function getInfo(address _attester) - external - view - override(IStaking) - returns (ValidatorInfo memory) - { - return StakingLib.getStorage().info[_attester]; - } - - function getExit(address _attester) external view override(IStaking) returns (Exit memory) { - return StakingLib.getStorage().exits[_attester]; - } - - function getOperatorAtIndex(uint256 _index) - external - view - override(IStaking) - returns (OperatorInfo memory) - { - address attester = StakingLib.getStorage().attesters.at(_index); - return - OperatorInfo({proposer: StakingLib.getStorage().info[attester].proposer, attester: attester}); - } - - /** - * @notice Get the validator set for a given epoch - * - * @dev Consider removing this to replace with a `size` and individual getter. - * - * @param _epoch The epoch number to get the validator set for - * - * @return The validator set for the given epoch - */ - function getEpochCommittee(Epoch _epoch) - external - view - override(IValidatorSelection) - returns (address[] memory) - { - return validatorSelectionStore.epochs[_epoch].committee; - } - - /** - * @notice Get the validator set for the current epoch - * @return The validator set for the current epoch - */ - function getCurrentEpochCommittee() - external - view - override(IValidatorSelection) - returns (address[] memory) - { - return ValidatorSelectionLib.getCommitteeAt( - validatorSelectionStore, StakingLib.getStorage(), getCurrentEpoch(), TARGET_COMMITTEE_SIZE - ); - } - - /** - * @notice Get the committee for a given timestamp - * - * @param _ts - The timestamp to get the committee for - * - * @return The committee for the given timestamp - */ - function getCommitteeAt(Timestamp _ts) - external - view - override(IValidatorSelection) - returns (address[] memory) - { - return ValidatorSelectionLib.getCommitteeAt( - validatorSelectionStore, StakingLib.getStorage(), getEpochAt(_ts), TARGET_COMMITTEE_SIZE - ); - } - - /** - * @notice Get the sample seed for a given timestamp - * - * @param _ts - The timestamp to get the sample seed for - * - * @return The sample seed for the given timestamp - */ - function getSampleSeedAt(Timestamp _ts) - external - view - override(IValidatorSelection) - returns (uint256) - { - return ValidatorSelectionLib.getSampleSeed(validatorSelectionStore, getEpochAt(_ts)); - } - - /** - * @notice Get the sample seed for the current epoch - * - * @return The sample seed for the current epoch - */ - function getCurrentSampleSeed() external view override(IValidatorSelection) returns (uint256) { - return ValidatorSelectionLib.getSampleSeed(validatorSelectionStore, getCurrentEpoch()); - } - - /** - * @notice Performs a setup of an epoch if needed. The setup will - * - Sample the validator set for the epoch - * - Set the seed for the epoch - * - Update the last seed - * - * @dev Since this is a reference optimising for simplicity, we ValidatorSelectionStore the actual validator set in the epoch structure. - * This is very heavy on gas, so start crying because the gas here will melt the poles - * https://i.giphy.com/U1aN4HTfJ2SmgB2BBK.webp - */ - function setupEpoch() public override(IValidatorSelection) { - Epoch epochNumber = getCurrentEpoch(); - EpochData storage epoch = validatorSelectionStore.epochs[epochNumber]; - - if (epoch.sampleSeed == 0) { - epoch.sampleSeed = ValidatorSelectionLib.getSampleSeed(validatorSelectionStore, epochNumber); - epoch.nextSeed = validatorSelectionStore.lastSeed = _computeNextSeed(epochNumber); - epoch.committee = ValidatorSelectionLib.sampleValidators( - StakingLib.getStorage(), epoch.sampleSeed, TARGET_COMMITTEE_SIZE - ); - } - } - - /** - * @notice Get the attester set - * - * @dev Consider removing this to replace with a `size` and individual getter. - * - * @return The validator set - */ - function getAttesters() public view override(IValidatorSelection) returns (address[] memory) { - return StakingLib.getStorage().attesters.values(); - } - - /** - * @notice Get the current epoch number - * - * @return The current epoch number - */ - function getCurrentEpoch() public view override(IValidatorSelection) returns (Epoch) { - return getEpochAt(Timestamp.wrap(block.timestamp)); - } - - /** - * @notice Get the current slot number - * - * @return The current slot number - */ - function getCurrentSlot() public view override(IValidatorSelection) returns (Slot) { - return getSlotAt(Timestamp.wrap(block.timestamp)); - } - - /** - * @notice Get the timestamp for a given slot - * - * @param _slotNumber - The slot number to get the timestamp for - * - * @return The timestamp for the given slot - */ - function getTimestampForSlot(Slot _slotNumber) - public - view - override(IValidatorSelection) - returns (Timestamp) - { - return _slotNumber.toTimestamp(); - } - - /** - * @notice Get the proposer for the current slot - * - * @dev Calls `getCurrentProposer(uint256)` with the current timestamp - * - * @return The address of the proposer - */ - function getCurrentProposer() public view override(IValidatorSelection) returns (address) { - return getProposerAt(Timestamp.wrap(block.timestamp)); - } - - /** - * @notice Get the proposer for the slot at a specific timestamp - * - * @dev This function is very useful for off-chain usage, as it easily allow a client to - * determine who will be the proposer at the NEXT ethereum block. - * Should not be trusted when moving beyond the current epoch, since changes to the - * validator set might not be reflected when we actually reach that epoch (more changes - * might have happened). - * - * @dev The proposer is selected from the validator set of the current epoch. - * - * @dev Should only be access on-chain if epoch is setup, otherwise very expensive. - * - * @dev A return value of address(0) means that the proposer is "open" and can be anyone. - * - * @dev If the current epoch is the first epoch, returns address(0) - * If the current epoch is setup, we will return the proposer for the current slot - * If the current epoch is not setup, we will perform a sample as if it was (gas heavy) - * - * @return The address of the proposer - */ - function getProposerAt(Timestamp _ts) public view override(IValidatorSelection) returns (address) { - Slot slot = getSlotAt(_ts); - Epoch epochNumber = getEpochAtSlot(slot); - return ValidatorSelectionLib.getProposerAt( - validatorSelectionStore, StakingLib.getStorage(), slot, epochNumber, TARGET_COMMITTEE_SIZE - ); - } - - /** - * @notice Computes the epoch at a specific time - * - * @param _ts - The timestamp to compute the epoch for - * - * @return The computed epoch - */ - function getEpochAt(Timestamp _ts) public view override(IValidatorSelection) returns (Epoch) { - return _ts.epochFromTimestamp(); - } - - /** - * @notice Computes the slot at a specific time - * - * @param _ts - The timestamp to compute the slot for - * - * @return The computed slot - */ - function getSlotAt(Timestamp _ts) public view override(IValidatorSelection) returns (Slot) { - return _ts.slotFromTimestamp(); - } - - /** - * @notice Computes the epoch at a specific slot - * - * @param _slotNumber - The slot number to compute the epoch for - * - * @return The computed epoch - */ - function getEpochAtSlot(Slot _slotNumber) - public - view - override(IValidatorSelection) - returns (Epoch) - { - return _slotNumber.epochFromSlot(); - } - - // Can be used to add validators without setting up the epoch, useful for the initial set. - function _cheat__Deposit( - address _attester, - address _proposer, - address _withdrawer, - uint256 _amount - ) internal { - require( - _attester != address(0) && _proposer != address(0), - Errors.ValidatorSelection__InvalidDeposit(_attester, _proposer) - ); - - StakingLib.deposit(_attester, _proposer, _withdrawer, _amount); - } - - /** - * @notice Propose a pending block from the point-of-view of sequencer selection. Will: - * - Setup the epoch if needed (if epoch committee is empty skips the rest) - * - Validate that the proposer is the proposer of the slot - * - Validate that the signatures for attestations are indeed from the validatorset - * - Validate that the number of valid attestations is sufficient - * - * @dev Cases where errors are thrown: - * - If the epoch is not setup - * - If the proposer is not the real proposer AND the proposer is not open - * - If the number of valid attestations is insufficient - * - * @param _slot - The slot of the block - * @param _signatures - The signatures of the committee members - * @param _digest - The digest of the block - */ - function _validateValidatorSelection( - Slot _slot, - Signature[] memory _signatures, - bytes32 _digest, - DataStructures.ExecutionFlags memory _flags - ) internal view { - Epoch epochNumber = getEpochAtSlot(_slot); - ValidatorSelectionLib.validateValidatorSelection( - validatorSelectionStore, - StakingLib.getStorage(), - _slot, - epochNumber, - _signatures, - _digest, - _flags, - TARGET_COMMITTEE_SIZE - ); - } - - /** - * @notice Computes the nextSeed for an epoch - * - * @dev We include the `_epoch` instead of using the randao directly to avoid issues with foundry testing - * where randao == 0. - * - * @param _epoch - The epoch to compute the seed for - * - * @return The computed seed - */ - function _computeNextSeed(Epoch _epoch) private view returns (uint256) { - return uint256(keccak256(abi.encode(_epoch, block.prevrandao))); - } -} diff --git a/l1-contracts/src/core/interfaces/IRollup.sol b/l1-contracts/src/core/interfaces/IRollup.sol index c8216166cf0..edda9efec3c 100644 --- a/l1-contracts/src/core/interfaces/IRollup.sol +++ b/l1-contracts/src/core/interfaces/IRollup.sol @@ -76,7 +76,7 @@ interface ITestRollup { returns (ManaBaseFeeComponents memory); } -interface IRollup { +interface IRollupCore { event L2BlockProposed( uint256 indexed blockNumber, bytes32 indexed archive, bytes32[] versionedBlobHashes ); @@ -112,17 +112,6 @@ interface IRollup { function submitEpochRootProof(SubmitEpochRootProofArgs calldata _args) external; - function canProposeAtTime(Timestamp _ts, bytes32 _archive) external view returns (Slot, uint256); - - function validateHeader( - bytes calldata _header, - Signature[] memory _signatures, - bytes32 _digest, - Timestamp _currentTime, - bytes32 _blobsHash, - DataStructures.ExecutionFlags memory _flags - ) external view; - // solhint-disable-next-line func-name-mixedcase function INBOX() external view returns (IInbox); @@ -132,7 +121,22 @@ interface IRollup { // solhint-disable-next-line func-name-mixedcase function L1_BLOCK_AT_GENESIS() external view returns (uint256); - function getProofClaim() external view returns (DataStructures.EpochProofClaim memory); + function quoteToDigest(EpochProofQuote memory _quote) external view returns (bytes32); + + function getFeeAssetPrice() external view returns (uint256); + function getL1FeesAt(Timestamp _timestamp) external view returns (L1FeeData memory); + + function canPrune() external view returns (bool); + function canPruneAtTime(Timestamp _ts) external view returns (bool); + function getEpochToProve() external view returns (Epoch); + + function validateEpochProofRightClaimAtTime(Timestamp _ts, SignedEpochProofQuote calldata _quote) + external + view; + function getEpochForBlock(uint256 _blockNumber) external view returns (Epoch); +} + +interface IRollup is IRollupCore { function getTips() external view returns (ChainTips memory); function status(uint256 _myHeaderBlockNumber) @@ -147,25 +151,8 @@ interface IRollup { Epoch provenEpochNumber ); - function quoteToDigest(EpochProofQuote memory _quote) external view returns (bytes32); - function getBlock(uint256 _blockNumber) external view returns (BlockLog memory); - function getFeeAssetPrice() external view returns (uint256); - function getManaBaseFeeAt(Timestamp _timestamp, bool _inFeeAsset) external view returns (uint256); - function getL1FeesAt(Timestamp _timestamp) external view returns (L1FeeData memory); + function getProofClaim() external view returns (DataStructures.EpochProofClaim memory); - function archive() external view returns (bytes32); - function archiveAt(uint256 _blockNumber) external view returns (bytes32); - function canPrune() external view returns (bool); - function canPruneAtTime(Timestamp _ts) external view returns (bool); - function getProvenBlockNumber() external view returns (uint256); - function getPendingBlockNumber() external view returns (uint256); - function getBlobPublicInputsHash(uint256 _blockNumber) external view returns (bytes32); - function getEpochToProve() external view returns (Epoch); - function getClaimableEpoch() external view returns (Epoch); - function validateEpochProofRightClaimAtTime(Timestamp _ts, SignedEpochProofQuote calldata _quote) - external - view; - function getEpochForBlock(uint256 _blockNumber) external view returns (Epoch); function getEpochProofPublicInputs( uint256 _epochSize, bytes32[7] calldata _args, @@ -173,8 +160,31 @@ interface IRollup { bytes calldata _blobPublicInputs, bytes calldata _aggregationObject ) external view returns (bytes32[] memory); + + function getClaimableEpoch() external view returns (Epoch); + + function validateHeader( + bytes calldata _header, + Signature[] memory _signatures, + bytes32 _digest, + Timestamp _currentTime, + bytes32 _blobsHash, + DataStructures.ExecutionFlags memory _flags + ) external view; + + function canProposeAtTime(Timestamp _ts, bytes32 _archive) external view returns (Slot, uint256); + function validateBlobs(bytes calldata _blobsInputs) external view returns (bytes32[] memory, bytes32, bytes32); + + function getManaBaseFeeAt(Timestamp _timestamp, bool _inFeeAsset) external view returns (uint256); + + function archive() external view returns (bytes32); + function archiveAt(uint256 _blockNumber) external view returns (bytes32); + function getProvenBlockNumber() external view returns (uint256); + function getPendingBlockNumber() external view returns (uint256); + function getBlock(uint256 _blockNumber) external view returns (BlockLog memory); + function getBlobPublicInputsHash(uint256 _blockNumber) external view returns (bytes32); } diff --git a/l1-contracts/src/core/interfaces/IStaking.sol b/l1-contracts/src/core/interfaces/IStaking.sol index a3a7414f605..3460af47db1 100644 --- a/l1-contracts/src/core/interfaces/IStaking.sol +++ b/l1-contracts/src/core/interfaces/IStaking.sol @@ -45,7 +45,7 @@ struct StakingStorage { mapping(address attester => Exit) exits; } -interface IStaking { +interface IStakingCore { event Deposit( address indexed attester, address indexed proposer, address indexed withdrawer, uint256 amount ); @@ -58,7 +58,9 @@ interface IStaking { function initiateWithdraw(address _attester, address _recipient) external returns (bool); function finaliseWithdraw(address _attester) external; function slash(address _attester, uint256 _amount) external; +} +interface IStaking is IStakingCore { function getInfo(address _attester) external view returns (ValidatorInfo memory); function getExit(address _attester) external view returns (Exit memory); function getActiveAttesterCount() external view returns (uint256); diff --git a/l1-contracts/src/core/interfaces/IValidatorSelection.sol b/l1-contracts/src/core/interfaces/IValidatorSelection.sol index 07dab165693..387abe16b66 100644 --- a/l1-contracts/src/core/interfaces/IValidatorSelection.sol +++ b/l1-contracts/src/core/interfaces/IValidatorSelection.sol @@ -21,11 +21,15 @@ struct ValidatorSelectionStorage { mapping(Epoch => EpochData) epochs; // The last stored randao value, same value as `seed` in the last inserted epoch uint256 lastSeed; + uint256 targetCommitteeSize; } -interface IValidatorSelection { - // Likely changing to optimize in Pleistarchus +interface IValidatorSelectionCore { function setupEpoch() external; +} + +interface IValidatorSelection is IValidatorSelectionCore { + // Likely changing to optimize in Pleistarchus function getCurrentProposer() external view returns (address); function getProposerAt(Timestamp _ts) external view returns (address); @@ -53,4 +57,5 @@ interface IValidatorSelection { function getGenesisTime() external view returns (Timestamp); function getSlotDuration() external view returns (uint256); function getEpochDuration() external view returns (uint256); + function getTargetCommitteeSize() external view returns (uint256); } diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 9084c90fa4b..afd700cc04a 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -109,6 +109,7 @@ library Errors { error Staking__AlreadyRegistered(address); // 0x18047699 error Staking__CannotSlashExitedStake(address); // 0x45bf4940 error Staking__FailedToRemove(address); // 0xa7d7baab + error Staking__InvalidDeposit(address attester, address proposer); // 0xf33fe8c6 error Staking__InsufficientStake(uint256, uint256); // 0x903aee24 error Staking__NoOneToSlash(address); // 0x7e2f7f1c error Staking__NotExiting(address); // 0xef566ee0 diff --git a/l1-contracts/src/core/libraries/RollupLibs/ValidationLib.sol b/l1-contracts/src/core/libraries/RollupLibs/ValidationLib.sol index 3738b5f7920..72931ba060e 100644 --- a/l1-contracts/src/core/libraries/RollupLibs/ValidationLib.sol +++ b/l1-contracts/src/core/libraries/RollupLibs/ValidationLib.sol @@ -9,6 +9,7 @@ import {SignatureLib} from "@aztec/core/libraries/crypto/SignatureLib.sol"; import {DataStructures} from "./../DataStructures.sol"; import {Errors} from "./../Errors.sol"; import {Timestamp, Slot, Epoch} from "./../TimeLib.sol"; +import {TimeLib} from "./../TimeLib.sol"; import {SignedEpochProofQuote} from "./EpochProofQuoteLib.sol"; import {Header} from "./HeaderLib.sol"; @@ -21,7 +22,6 @@ struct ValidateHeaderArgs { DataStructures.ExecutionFlags flags; uint256 version; IFeeJuicePortal feeJuicePortal; - function(Slot) external view returns (Timestamp) getTimestampForSlot; } library ValidationLib { @@ -56,7 +56,7 @@ library ValidationLib { Slot lastSlot = _blocks[_args.pendingBlockNumber].slotNumber; require(slot > lastSlot, Errors.Rollup__SlotAlreadyInChain(lastSlot, slot)); - Timestamp timestamp = _args.getTimestampForSlot(slot); + Timestamp timestamp = TimeLib.toTimestamp(slot); require( Timestamp.wrap(_args.header.globalVariables.timestamp) == timestamp, Errors.Rollup__InvalidTimestamp( diff --git a/l1-contracts/src/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol b/l1-contracts/src/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol index 981b7d92b2e..d2830f4a8cd 100644 --- a/l1-contracts/src/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol +++ b/l1-contracts/src/core/libraries/ValidatorSelectionLib/ValidatorSelectionLib.sol @@ -10,7 +10,7 @@ import {SampleLib} from "@aztec/core/libraries/crypto/SampleLib.sol"; import {SignatureLib, Signature} from "@aztec/core/libraries/crypto/SignatureLib.sol"; import {DataStructures} from "@aztec/core/libraries/DataStructures.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; -import {Slot, Epoch} from "@aztec/core/libraries/TimeLib.sol"; +import {Timestamp, Slot, Epoch, TimeLib} from "@aztec/core/libraries/TimeLib.sol"; import {MessageHashUtils} from "@oz/utils/cryptography/MessageHashUtils.sol"; import {EnumerableSet} from "@oz/utils/structs/EnumerableSet.sol"; @@ -18,43 +18,31 @@ library ValidatorSelectionLib { using EnumerableSet for EnumerableSet.AddressSet; using MessageHashUtils for bytes32; using SignatureLib for Signature; + using TimeLib for Timestamp; + + bytes32 private constant VALIDATOR_SELECTION_STORAGE_POSITION = + keccak256("aztec.validator_selection.storage"); /** - * @notice Samples a validator set for a specific epoch - * - * @dev Only used internally, should never be called for anything but the "next" epoch - * Allowing us to always use `lastSeed`. + * @notice Performs a setup of an epoch if needed. The setup will + * - Sample the validator set for the epoch + * - Set the seed for the epoch + * - Update the last seed * - * @return The validators for the given epoch + * @dev Since this is a reference optimising for simplicity, we store the actual validator set in the epoch structure. + * This is very heavy on gas, so start crying because the gas here will melt the poles + * https://i.giphy.com/U1aN4HTfJ2SmgB2BBK.webp */ - function sampleValidators( - StakingStorage storage _stakingStore, - uint256 _seed, - uint256 _targetCommitteeSize - ) external view returns (address[] memory) { - return _sampleValidators(_stakingStore, _seed, _targetCommitteeSize); - } + function setupEpoch(StakingStorage storage _stakingStore) external { + Epoch epochNumber = Timestamp.wrap(block.timestamp).epochFromTimestamp(); + ValidatorSelectionStorage storage store = getStorage(); + EpochData storage epoch = store.epochs[epochNumber]; - function getProposerAt( - ValidatorSelectionStorage storage _validatorSelectionStore, - StakingStorage storage _stakingStore, - Slot _slot, - Epoch _epochNumber, - uint256 _targetCommitteeSize - ) external view returns (address) { - return _getProposerAt( - _validatorSelectionStore, _stakingStore, _slot, _epochNumber, _targetCommitteeSize - ); - } - - function getCommitteeAt( - ValidatorSelectionStorage storage _validatorSelectionStore, - StakingStorage storage _stakingStore, - Epoch _epochNumber, - uint256 _targetCommitteeSize - ) external view returns (address[] memory) { - return - _getCommitteeAt(_validatorSelectionStore, _stakingStore, _epochNumber, _targetCommitteeSize); + if (epoch.sampleSeed == 0) { + epoch.sampleSeed = getSampleSeed(epochNumber); + epoch.nextSeed = store.lastSeed = computeNextSeed(epochNumber); + epoch.committee = sampleValidators(_stakingStore, epoch.sampleSeed); + } } /** @@ -74,23 +62,20 @@ library ValidatorSelectionLib { * @param _digest - The digest of the block */ function validateValidatorSelection( - ValidatorSelectionStorage storage _validatorSelectionStore, StakingStorage storage _stakingStore, Slot _slot, Epoch _epochNumber, Signature[] memory _signatures, bytes32 _digest, - DataStructures.ExecutionFlags memory _flags, - uint256 _targetCommitteeSize + DataStructures.ExecutionFlags memory _flags ) external view { // Same logic as we got in getProposerAt // Done do avoid duplicate computing the committee - address[] memory committee = - _getCommitteeAt(_validatorSelectionStore, _stakingStore, _epochNumber, _targetCommitteeSize); + address[] memory committee = getCommitteeAt(_stakingStore, _epochNumber); address attester = committee.length == 0 ? address(0) : committee[computeProposerIndex( - _epochNumber, _slot, getSampleSeed(_validatorSelectionStore, _epochNumber), committee.length + _epochNumber, _slot, getSampleSeed(_epochNumber), committee.length )]; address proposer = _stakingStore.info[attester].proposer; @@ -137,39 +122,25 @@ library ValidatorSelectionLib { ); } - /** - * @notice Get the sample seed for an epoch - * - * @dev This should behave as walking past the line, but it does not currently do that. - * If there are entire skips, e.g., 1, 2, 5 and we then go back and try executing - * for 4 we will get an invalid value because we will read lastSeed which is from 5. - * - * @dev The `_epoch` will never be 0 nor in the future - * - * @dev The return value will be equal to keccak256(n, block.prevrandao) for n being the last epoch - * setup. - * - * @return The sample seed for the epoch - */ - function getSampleSeed(ValidatorSelectionStorage storage _validatorSelectionStore, Epoch _epoch) - internal + function getProposerAt(StakingStorage storage _stakingStore, Slot _slot, Epoch _epochNumber) + external view - returns (uint256) + returns (address) { - if (Epoch.unwrap(_epoch) == 0) { - return type(uint256).max; - } - uint256 sampleSeed = _validatorSelectionStore.epochs[_epoch].sampleSeed; - if (sampleSeed != 0) { - return sampleSeed; + // @note this is deliberately "bad" for the simple reason of code reduction. + // it does not need to actually return the full committee and then draw from it + // it can just return the proposer directly, but then we duplicate the code + // which we just don't have room for right now... + address[] memory committee = getCommitteeAt(_stakingStore, _epochNumber); + if (committee.length == 0) { + return address(0); } - sampleSeed = _validatorSelectionStore.epochs[_epoch - Epoch.wrap(1)].nextSeed; - if (sampleSeed != 0) { - return sampleSeed; - } + address attester = committee[computeProposerIndex( + _epochNumber, _slot, getSampleSeed(_epochNumber), committee.length + )]; - return _validatorSelectionStore.lastSeed; + return _stakingStore.info[attester].proposer; } /** @@ -180,62 +151,41 @@ library ValidatorSelectionLib { * * @return The validators for the given epoch */ - function _sampleValidators( - StakingStorage storage _stakingStore, - uint256 _seed, - uint256 _targetCommitteeSize - ) private view returns (address[] memory) { + function sampleValidators(StakingStorage storage _stakingStore, uint256 _seed) + public + view + returns (address[] memory) + { uint256 validatorSetSize = _stakingStore.attesters.length(); if (validatorSetSize == 0) { return new address[](0); } + ValidatorSelectionStorage storage store = getStorage(); + uint256 targetCommitteeSize = store.targetCommitteeSize; + // If we have less validators than the target committee size, we just return the full set - if (validatorSetSize <= _targetCommitteeSize) { + if (validatorSetSize <= targetCommitteeSize) { return _stakingStore.attesters.values(); } uint256[] memory indices = - SampleLib.computeCommitteeClever(_targetCommitteeSize, validatorSetSize, _seed); + SampleLib.computeCommitteeClever(targetCommitteeSize, validatorSetSize, _seed); - address[] memory committee = new address[](_targetCommitteeSize); - for (uint256 i = 0; i < _targetCommitteeSize; i++) { + address[] memory committee = new address[](targetCommitteeSize); + for (uint256 i = 0; i < targetCommitteeSize; i++) { committee[i] = _stakingStore.attesters.at(indices[i]); } return committee; } - function _getProposerAt( - ValidatorSelectionStorage storage _validatorSelectionStore, - StakingStorage storage _stakingStore, - Slot _slot, - Epoch _epochNumber, - uint256 _targetCommitteeSize - ) private view returns (address) { - // @note this is deliberately "bad" for the simple reason of code reduction. - // it does not need to actually return the full committee and then draw from it - // it can just return the proposer directly, but then we duplicate the code - // which we just don't have room for right now... - address[] memory committee = - _getCommitteeAt(_validatorSelectionStore, _stakingStore, _epochNumber, _targetCommitteeSize); - if (committee.length == 0) { - return address(0); - } - - address attester = committee[computeProposerIndex( - _epochNumber, _slot, getSampleSeed(_validatorSelectionStore, _epochNumber), committee.length - )]; - - return _stakingStore.info[attester].proposer; - } - - function _getCommitteeAt( - ValidatorSelectionStorage storage _validatorSelectionStore, - StakingStorage storage _stakingStore, - Epoch _epochNumber, - uint256 _targetCommitteeSize - ) private view returns (address[] memory) { - EpochData storage epoch = _validatorSelectionStore.epochs[_epochNumber]; + function getCommitteeAt(StakingStorage storage _stakingStore, Epoch _epochNumber) + public + view + returns (address[] memory) + { + ValidatorSelectionStorage storage store = getStorage(); + EpochData storage epoch = store.epochs[_epochNumber]; if (epoch.sampleSeed != 0) { uint256 committeeSize = epoch.committee.length; @@ -251,8 +201,66 @@ library ValidatorSelectionLib { } // Emulate a sampling of the validators - uint256 sampleSeed = getSampleSeed(_validatorSelectionStore, _epochNumber); - return _sampleValidators(_stakingStore, sampleSeed, _targetCommitteeSize); + uint256 sampleSeed = getSampleSeed(_epochNumber); + return sampleValidators(_stakingStore, sampleSeed); + } + + function initialize(uint256 _targetCommitteeSize) internal { + ValidatorSelectionStorage storage store = getStorage(); + store.targetCommitteeSize = _targetCommitteeSize; + } + + /** + * @notice Get the sample seed for an epoch + * + * @dev This should behave as walking past the line, but it does not currently do that. + * If there are entire skips, e.g., 1, 2, 5 and we then go back and try executing + * for 4 we will get an invalid value because we will read lastSeed which is from 5. + * + * @dev The `_epoch` will never be 0 nor in the future + * + * @dev The return value will be equal to keccak256(n, block.prevrandao) for n being the last epoch + * setup. + * + * @return The sample seed for the epoch + */ + function getSampleSeed(Epoch _epoch) internal view returns (uint256) { + if (Epoch.unwrap(_epoch) == 0) { + return type(uint256).max; + } + ValidatorSelectionStorage storage store = getStorage(); + uint256 sampleSeed = store.epochs[_epoch].sampleSeed; + if (sampleSeed != 0) { + return sampleSeed; + } + + sampleSeed = store.epochs[_epoch - Epoch.wrap(1)].nextSeed; + if (sampleSeed != 0) { + return sampleSeed; + } + + return store.lastSeed; + } + + function getStorage() internal pure returns (ValidatorSelectionStorage storage storageStruct) { + bytes32 position = VALIDATOR_SELECTION_STORAGE_POSITION; + assembly { + storageStruct.slot := position + } + } + + /** + * @notice Computes the nextSeed for an epoch + * + * @dev We include the `_epoch` instead of using the randao directly to avoid issues with foundry testing + * where randao == 0. + * + * @param _epoch - The epoch to compute the seed for + * + * @return The computed seed + */ + function computeNextSeed(Epoch _epoch) private view returns (uint256) { + return uint256(keccak256(abi.encode(_epoch, block.prevrandao))); } /** diff --git a/l1-contracts/src/core/libraries/staking/StakingLib.sol b/l1-contracts/src/core/libraries/staking/StakingLib.sol index 0071f09b626..6c02dfdf54d 100644 --- a/l1-contracts/src/core/libraries/staking/StakingLib.sol +++ b/l1-contracts/src/core/libraries/staking/StakingLib.sol @@ -7,9 +7,9 @@ import { ValidatorInfo, Exit, Timestamp, - StakingStorage + StakingStorage, + IStakingCore } from "@aztec/core/interfaces/IStaking.sol"; -import {IStaking} from "@aztec/core/interfaces/IStaking.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; @@ -53,7 +53,7 @@ library StakingLib { store.stakingAsset.transfer(recipient, amount); - emit IStaking.WithdrawFinalised(_attester, recipient, amount); + emit IStakingCore.WithdrawFinalised(_attester, recipient, amount); } function slash(address _attester, uint256 _amount) external { @@ -81,12 +81,16 @@ library StakingLib { validator.status = Status.LIVING; } - emit IStaking.Slashed(_attester, _amount); + emit IStakingCore.Slashed(_attester, _amount); } function deposit(address _attester, address _proposer, address _withdrawer, uint256 _amount) external { + require( + _attester != address(0) && _proposer != address(0), + Errors.Staking__InvalidDeposit(_attester, _proposer) + ); StakingStorage storage store = getStorage(); require( _amount >= store.minimumStake, Errors.Staking__InsufficientStake(_amount, store.minimumStake) @@ -106,7 +110,7 @@ library StakingLib { status: Status.VALIDATING }); - emit IStaking.Deposit(_attester, _proposer, _withdrawer, _amount); + emit IStakingCore.Deposit(_attester, _proposer, _withdrawer, _amount); } function initiateWithdraw(address _attester, address _recipient) external returns (bool) { @@ -131,7 +135,7 @@ library StakingLib { Exit({exitableAt: Timestamp.wrap(block.timestamp) + store.exitDelay, recipient: _recipient}); validator.status = Status.EXITING; - emit IStaking.WithdrawInitiated(_attester, _recipient, validator.stake); + emit IStakingCore.WithdrawInitiated(_attester, _recipient, validator.stake); return true; } diff --git a/l1-contracts/src/periphery/Forwarder.sol b/l1-contracts/src/periphery/Forwarder.sol index a921b2ab500..0f3673336e2 100644 --- a/l1-contracts/src/periphery/Forwarder.sol +++ b/l1-contracts/src/periphery/Forwarder.sol @@ -11,7 +11,11 @@ contract Forwarder is Ownable, IForwarder { constructor(address __owner) Ownable(__owner) {} - function forward(address[] calldata _to, bytes[] calldata _data) external override onlyOwner { + function forward(address[] calldata _to, bytes[] calldata _data) + external + override(IForwarder) + onlyOwner + { require( _to.length == _data.length, IForwarder.ForwarderLengthMismatch(_to.length, _data.length) ); diff --git a/l1-contracts/src/periphery/SlashPayload.sol b/l1-contracts/src/periphery/SlashPayload.sol index b39fcb8301c..e9c429dc5e8 100644 --- a/l1-contracts/src/periphery/SlashPayload.sol +++ b/l1-contracts/src/periphery/SlashPayload.sol @@ -2,7 +2,7 @@ // Copyright 2024 Aztec Labs. pragma solidity >=0.8.27; -import {IStaking} from "@aztec/core/interfaces/IStaking.sol"; +import {IStakingCore} from "@aztec/core/interfaces/IStaking.sol"; import {IValidatorSelection} from "@aztec/core/interfaces/IValidatorSelection.sol"; import {Epoch} from "@aztec/core/libraries/TimeLib.sol"; import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; @@ -28,7 +28,7 @@ contract SlashPayload is IPayload { for (uint256 i = 0; i < attesters.length; i++) { actions[i] = IPayload.Action({ target: address(VALIDATOR_SELECTION), - data: abi.encodeWithSelector(IStaking.slash.selector, attesters[i], AMOUNT) + data: abi.encodeWithSelector(IStakingCore.slash.selector, attesters[i], AMOUNT) }); } diff --git a/l1-contracts/test/Forwarder.t.sol b/l1-contracts/test/Forwarder.t.sol index 8599dcca51f..0470dbb4c8f 100644 --- a/l1-contracts/test/Forwarder.t.sol +++ b/l1-contracts/test/Forwarder.t.sol @@ -66,9 +66,8 @@ contract ForwarderTest is Test { } function testRevertWhenCallToInvalidAddress(address _invalidAddress) public { - vm.assume(_invalidAddress != address(token1)); - vm.assume(_invalidAddress != address(token2)); - vm.assume(_invalidAddress != address(forwarder)); + vm.assume(_invalidAddress.code.length == 0); + vm.assume(uint160(_invalidAddress) > uint160(0x0a)); address[] memory targets = new address[](1); targets[0] = _invalidAddress; diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index ad454786e91..3439bd957cf 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -18,10 +18,9 @@ import {Inbox} from "@aztec/core/messagebridge/Inbox.sol"; import {Outbox} from "@aztec/core/messagebridge/Outbox.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {Rollup} from "./harnesses/Rollup.sol"; -import {IRollup, BlockLog, SubmitEpochRootProofArgs} from "@aztec/core/interfaces/IRollup.sol"; +import {IRollupCore, BlockLog, SubmitEpochRootProofArgs} from "@aztec/core/interfaces/IRollup.sol"; import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol"; import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol"; -import {ValidatorSelection} from "@aztec/core/ValidatorSelection.sol"; import {NaiveMerkle} from "./merkle/Naive.sol"; import {MerkleTestUtil} from "./merkle/TestUtil.sol"; import {TestERC20} from "@aztec/mock/TestERC20.sol"; @@ -54,7 +53,6 @@ contract RollupTest is DecoderBase { Inbox internal inbox; Outbox internal outbox; Rollup internal rollup; - ValidatorSelection internal leo; MerkleTestUtil internal merkleTestUtil; TestERC20 internal testERC20; FeeJuicePortal internal feeJuicePortal; @@ -86,15 +84,6 @@ contract RollupTest is DecoderBase { { testERC20 = new TestERC20("test", "TEST", address(this)); - leo = new ValidatorSelection( - testERC20, - TestConstants.AZTEC_MINIMUM_STAKE, - TestConstants.AZTEC_SLASHING_QUORUM, - TestConstants.AZTEC_SLASHING_ROUND_SIZE, - TestConstants.AZTEC_SLOT_DURATION, - TestConstants.AZTEC_EPOCH_DURATION, - TestConstants.AZTEC_TARGET_COMMITTEE_SIZE - ); DecoderBase.Full memory full = load(_name); uint256 slotNumber = full.block.decodedHeader.globalVariables.slotNumber; uint256 initialTime = @@ -273,7 +262,7 @@ contract RollupTest is DecoderBase { _testBlock("mixed_block_1", false, 1); vm.expectEmit(true, true, true, true); - emit IRollup.ProofRightClaimed( + emit IRollupCore.ProofRightClaimed( quote.epochToProve, quote.prover, address(this), quote.bondAmount, Slot.wrap(1) ); rollup.claimEpochProofRight(signedQuote); @@ -455,7 +444,7 @@ contract RollupTest is DecoderBase { signedQuote = _quoteToSignedQuote(quote); vm.expectEmit(true, true, true, true); - emit IRollup.ProofRightClaimed( + emit IRollupCore.ProofRightClaimed( quote.epochToProve, quote.prover, address(this), quote.bondAmount, Epoch.wrap(3).toSlots() ); rollup.claimEpochProofRight(signedQuote); diff --git a/l1-contracts/test/base/Base.sol b/l1-contracts/test/base/Base.sol index 52d175faeab..5d646d20cea 100644 --- a/l1-contracts/test/base/Base.sol +++ b/l1-contracts/test/base/Base.sol @@ -230,6 +230,6 @@ contract TestBase is Test { // and looking in the logs. Interesting. // Alternative, run forge inspect src/core/Rollup.sol:Rollup storageLayout --pretty // uint256 slot = stdstore.target(address(rollup)).sig("checkBlob()").find(); - vm.store(address(rollup), bytes32(uint256(5)), bytes32(uint256(0))); + vm.store(address(rollup), bytes32(uint256(4)), bytes32(uint256(0))); } } diff --git a/l1-contracts/test/fees/FeeRollup.t.sol b/l1-contracts/test/fees/FeeRollup.t.sol index c79eaa05032..8093c87f261 100644 --- a/l1-contracts/test/fees/FeeRollup.t.sol +++ b/l1-contracts/test/fees/FeeRollup.t.sol @@ -26,7 +26,6 @@ import { import {IRollup} from "@aztec/core/interfaces/IRollup.sol"; import {IProofCommitmentEscrow} from "@aztec/core/interfaces/IProofCommitmentEscrow.sol"; import {FeeJuicePortal} from "@aztec/core/FeeJuicePortal.sol"; -import {ValidatorSelection} from "@aztec/core/ValidatorSelection.sol"; import {NaiveMerkle} from "../merkle/Naive.sol"; import {MerkleTestUtil} from "../merkle/TestUtil.sol"; import {TestERC20} from "@aztec/mock/TestERC20.sol"; diff --git a/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol b/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol index 9ccdcc234ef..817269c4c20 100644 --- a/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol +++ b/l1-contracts/test/governance/governance-proposer/executeProposal.t.sol @@ -4,17 +4,17 @@ pragma solidity >=0.8.27; import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; import {IGovernanceProposer} from "@aztec/governance/interfaces/IGovernanceProposer.sol"; import {GovernanceProposerBase} from "./Base.t.sol"; -import {ValidatorSelection} from "../../harnesses/ValidatorSelection.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; import {Slot, SlotLib, Timestamp} from "@aztec/core/libraries/TimeLib.sol"; import {FaultyGovernance} from "./mocks/FaultyGovernance.sol"; import {FalsyGovernance} from "./mocks/FalsyGovernance.sol"; +import {Fakerollup} from "./mocks/Fakerollup.sol"; contract ExecuteProposalTest is GovernanceProposerBase { using SlotLib for Slot; - ValidatorSelection internal validatorSelection; + Fakerollup internal validatorSelection; IPayload internal proposal = IPayload(address(this)); address internal proposer = address(0); @@ -30,7 +30,7 @@ contract ExecuteProposalTest is GovernanceProposerBase { } modifier givenCanonicalInstanceHoldCode() { - validatorSelection = new ValidatorSelection(); + validatorSelection = new Fakerollup(); vm.prank(registry.getGovernance()); registry.upgrade(address(validatorSelection)); @@ -221,7 +221,7 @@ contract ExecuteProposalTest is GovernanceProposerBase { // it revert // When using a new registry we change the governanceProposer's interpetation of time :O - ValidatorSelection freshInstance = new ValidatorSelection(); + Fakerollup freshInstance = new Fakerollup(); vm.prank(registry.getGovernance()); registry.upgrade(address(freshInstance)); diff --git a/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol b/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol new file mode 100644 index 00000000000..cc4ee196a75 --- /dev/null +++ b/l1-contracts/test/governance/governance-proposer/mocks/Fakerollup.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.27; + +import { + Timestamp, Slot, Epoch, SlotLib, EpochLib, TimeLib +} from "@aztec/core/libraries/TimeLib.sol"; +import {TestConstants} from "../../../harnesses/TestConstants.sol"; + +contract Fakerollup { + using TimeLib for Slot; + using TimeLib for Timestamp; + + constructor() { + TimeLib.initialize( + block.timestamp, TestConstants.AZTEC_SLOT_DURATION, TestConstants.AZTEC_EPOCH_DURATION + ); + } + + function getTimestampForSlot(Slot _slot) external view returns (Timestamp) { + return _slot.toTimestamp(); + } + + function getCurrentSlot() external view returns (Slot) { + return Timestamp.wrap(block.timestamp).slotFromTimestamp(); + } + + function getGenesisTime() external view returns (Timestamp) { + return Timestamp.wrap(TimeLib.getStorage().genesisTime); + } + + function getSlotDuration() external view returns (uint256) { + return TimeLib.getStorage().slotDuration; + } + + function getEpochDuration() external view returns (uint256) { + return TimeLib.getStorage().epochDuration; + } + + function getCurrentProposer() external pure returns (address) { + return address(0); + } +} diff --git a/l1-contracts/test/governance/governance-proposer/vote.t.sol b/l1-contracts/test/governance/governance-proposer/vote.t.sol index 00144b652b5..89ba7e4a6ad 100644 --- a/l1-contracts/test/governance/governance-proposer/vote.t.sol +++ b/l1-contracts/test/governance/governance-proposer/vote.t.sol @@ -4,16 +4,16 @@ pragma solidity >=0.8.27; import {IPayload} from "@aztec/governance/interfaces/IPayload.sol"; import {IGovernanceProposer} from "@aztec/governance/interfaces/IGovernanceProposer.sol"; import {GovernanceProposerBase} from "./Base.t.sol"; -import {ValidatorSelection} from "../../harnesses/ValidatorSelection.sol"; import {Errors} from "@aztec/governance/libraries/Errors.sol"; import {Slot, SlotLib, Timestamp} from "@aztec/core/libraries/TimeLib.sol"; +import {Fakerollup} from "./mocks/Fakerollup.sol"; contract VoteTest is GovernanceProposerBase { using SlotLib for Slot; IPayload internal proposal = IPayload(address(0xdeadbeef)); address internal proposer = address(0); - ValidatorSelection internal validatorSelection; + Fakerollup internal validatorSelection; // Skipping this test since the it matches the for now skipped check in `EmpireBase::vote` function skip__test_WhenProposalHoldNoCode() external { @@ -40,7 +40,7 @@ contract VoteTest is GovernanceProposerBase { } modifier givenCanonicalRollupHoldCode() { - validatorSelection = new ValidatorSelection(); + validatorSelection = new Fakerollup(); vm.prank(registry.getGovernance()); registry.upgrade(address(validatorSelection)); @@ -144,7 +144,7 @@ contract VoteTest is GovernanceProposerBase { uint256 yeaBefore = governanceProposer.yeaCount(address(validatorSelection), validatorSelectionRound, proposal); - ValidatorSelection freshInstance = new ValidatorSelection(); + Fakerollup freshInstance = new Fakerollup(); vm.prank(registry.getGovernance()); registry.upgrade(address(freshInstance)); diff --git a/l1-contracts/test/harnesses/ValidatorSelection.sol b/l1-contracts/test/harnesses/ValidatorSelection.sol deleted file mode 100644 index 1ff93546cfa..00000000000 --- a/l1-contracts/test/harnesses/ValidatorSelection.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.27; - -import {ValidatorSelection as RealValidatorSelection} from "@aztec/core/ValidatorSelection.sol"; -import {TestConstants} from "./TestConstants.sol"; -import {TestERC20} from "@aztec/mock/TestERC20.sol"; - -contract ValidatorSelection is RealValidatorSelection { - constructor() - RealValidatorSelection( - new TestERC20("test", "TEST", address(this)), - 100e18, - TestConstants.AZTEC_SLASHING_QUORUM, - TestConstants.AZTEC_SLASHING_ROUND_SIZE, - TestConstants.AZTEC_SLOT_DURATION, - TestConstants.AZTEC_EPOCH_DURATION, - TestConstants.AZTEC_TARGET_COMMITTEE_SIZE - ) - {} -} diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 7f4060be639..b74fab88761 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -22,7 +22,10 @@ import {UniswapPortal} from "./UniswapPortal.sol"; import {MockFeeJuicePortal} from "@aztec/mock/MockFeeJuicePortal.sol"; import {RewardDistributor} from "@aztec/governance/RewardDistributor.sol"; +import {stdStorage, StdStorage} from "forge-std/Test.sol"; + contract UniswapPortalTest is Test { + using stdStorage for StdStorage; using Hash for DataStructures.L2ToL1Msg; IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); @@ -70,6 +73,8 @@ contract UniswapPortalTest is Test { // Modify the proven block count vm.store(address(rollup), bytes32(uint256(13)), bytes32(l2BlockNumber + 1)); + + stdstore.target(address(rollup)).sig("getProvenBlockNumber()").checked_write(l2BlockNumber + 1); assertEq(rollup.getProvenBlockNumber(), l2BlockNumber + 1); // have DAI locked in portal that can be moved when funds are withdrawn diff --git a/l1-contracts/test/staking/deposit.t.sol b/l1-contracts/test/staking/deposit.t.sol index ac2f51be3ec..0c743693492 100644 --- a/l1-contracts/test/staking/deposit.t.sol +++ b/l1-contracts/test/staking/deposit.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.27; import {StakingBase} from "./base.t.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {IERC20Errors} from "@oz/interfaces/draft-IERC6093.sol"; -import {IStaking, Status, ValidatorInfo} from "@aztec/core/interfaces/IStaking.sol"; +import {IStakingCore, Status, ValidatorInfo} from "@aztec/core/interfaces/IStaking.sol"; contract DepositTest is StakingBase { uint256 internal depositAmount; @@ -147,7 +147,7 @@ contract DepositTest is StakingBase { assertEq(stakingAsset.balanceOf(address(staking)), 0); vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.Deposit(ATTESTER, PROPOSER, WITHDRAWER, depositAmount); + emit IStakingCore.Deposit(ATTESTER, PROPOSER, WITHDRAWER, depositAmount); staking.deposit({ _attester: ATTESTER, diff --git a/l1-contracts/test/staking/finaliseWithdraw.t.sol b/l1-contracts/test/staking/finaliseWithdraw.t.sol index 1cdde4fcddb..4dc11259cae 100644 --- a/l1-contracts/test/staking/finaliseWithdraw.t.sol +++ b/l1-contracts/test/staking/finaliseWithdraw.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.27; import {StakingBase} from "./base.t.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import { - Timestamp, Status, ValidatorInfo, Exit, IStaking + Timestamp, Status, ValidatorInfo, Exit, IStakingCore } from "@aztec/core/interfaces/IStaking.sol"; contract FinaliseWithdrawTest is StakingBase { @@ -69,7 +69,7 @@ contract FinaliseWithdrawTest is StakingBase { vm.warp(Timestamp.unwrap(exit.exitableAt)); vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.WithdrawFinalised(ATTESTER, RECIPIENT, MINIMUM_STAKE); + emit IStakingCore.WithdrawFinalised(ATTESTER, RECIPIENT, MINIMUM_STAKE); staking.finaliseWithdraw(ATTESTER); exit = staking.getExit(ATTESTER); diff --git a/l1-contracts/test/staking/initiateWithdraw.t.sol b/l1-contracts/test/staking/initiateWithdraw.t.sol index fe69c47c7d1..cb93ad8ed3f 100644 --- a/l1-contracts/test/staking/initiateWithdraw.t.sol +++ b/l1-contracts/test/staking/initiateWithdraw.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.27; import {StakingBase} from "./base.t.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import { - Timestamp, Status, ValidatorInfo, Exit, IStaking + Timestamp, Status, ValidatorInfo, Exit, IStakingCore } from "@aztec/core/interfaces/IStaking.sol"; contract InitiateWithdrawTest is StakingBase { @@ -105,7 +105,7 @@ contract InitiateWithdrawTest is StakingBase { assertEq(staking.getActiveAttesterCount(), 1); vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.WithdrawInitiated(ATTESTER, RECIPIENT, MINIMUM_STAKE); + emit IStakingCore.WithdrawInitiated(ATTESTER, RECIPIENT, MINIMUM_STAKE); vm.prank(WITHDRAWER); staking.initiateWithdraw(ATTESTER, RECIPIENT); @@ -138,7 +138,7 @@ contract InitiateWithdrawTest is StakingBase { assertEq(staking.getActiveAttesterCount(), 0); vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.WithdrawInitiated(ATTESTER, RECIPIENT, MINIMUM_STAKE); + emit IStakingCore.WithdrawInitiated(ATTESTER, RECIPIENT, MINIMUM_STAKE); vm.prank(WITHDRAWER); staking.initiateWithdraw(ATTESTER, RECIPIENT); diff --git a/l1-contracts/test/staking/slash.t.sol b/l1-contracts/test/staking/slash.t.sol index d0cfe2e4364..1d3279ac7a8 100644 --- a/l1-contracts/test/staking/slash.t.sol +++ b/l1-contracts/test/staking/slash.t.sol @@ -4,7 +4,7 @@ pragma solidity >=0.8.27; import {StakingBase} from "./base.t.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import { - IStaking, Status, ValidatorInfo, Exit, Timestamp + IStakingCore, Status, ValidatorInfo, Exit, Timestamp } from "@aztec/core/interfaces/IStaking.sol"; contract SlashTest is StakingBase { @@ -83,7 +83,7 @@ contract SlashTest is StakingBase { assertTrue(info.status == Status.EXITING); vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.Slashed(ATTESTER, 1); + emit IStakingCore.Slashed(ATTESTER, 1); vm.prank(SLASHER); staking.slash(ATTESTER, 1); @@ -113,7 +113,7 @@ contract SlashTest is StakingBase { uint256 balance = info.stake; vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.Slashed(ATTESTER, 1); + emit IStakingCore.Slashed(ATTESTER, 1); vm.prank(SLASHER); staking.slash(ATTESTER, 1); @@ -163,7 +163,7 @@ contract SlashTest is StakingBase { uint256 balance = info.stake; vm.expectEmit(true, true, true, true, address(staking)); - emit IStaking.Slashed(ATTESTER, slashingAmount); + emit IStakingCore.Slashed(ATTESTER, slashingAmount); vm.prank(SLASHER); staking.slash(ATTESTER, slashingAmount); diff --git a/l1-contracts/test/validator-selection/ValidatorSelection.t.sol b/l1-contracts/test/validator-selection/ValidatorSelection.t.sol index adcf5ceef4e..46fd1bea36c 100644 --- a/l1-contracts/test/validator-selection/ValidatorSelection.t.sol +++ b/l1-contracts/test/validator-selection/ValidatorSelection.t.sol @@ -13,7 +13,6 @@ import {Outbox} from "@aztec/core/messagebridge/Outbox.sol"; import {Errors} from "@aztec/core/libraries/Errors.sol"; import {Registry} from "@aztec/governance/Registry.sol"; import {Rollup, Config} from "@aztec/core/Rollup.sol"; -import {ValidatorSelection} from "@aztec/core/ValidatorSelection.sol"; import {NaiveMerkle} from "../merkle/Naive.sol"; import {MerkleTestUtil} from "../merkle/TestUtil.sol"; import {TestERC20} from "@aztec/mock/TestERC20.sol"; @@ -69,20 +68,10 @@ contract ValidatorSelectionTest is DecoderBase { modifier setup(uint256 _validatorCount) { string memory _name = "mixed_block_1"; { - ValidatorSelection validatorSelection = new ValidatorSelection( - testERC20, - TestConstants.AZTEC_MINIMUM_STAKE, - TestConstants.AZTEC_SLASHING_QUORUM, - TestConstants.AZTEC_SLASHING_ROUND_SIZE, - TestConstants.AZTEC_SLOT_DURATION, - TestConstants.AZTEC_EPOCH_DURATION, - TestConstants.AZTEC_TARGET_COMMITTEE_SIZE - ); - DecoderBase.Full memory full = load(_name); uint256 slotNumber = full.block.decodedHeader.globalVariables.slotNumber; uint256 initialTime = full.block.decodedHeader.globalVariables.timestamp - - slotNumber * validatorSelection.getSlotDuration(); + - slotNumber * TestConstants.AZTEC_SLOT_DURATION; vm.warp(initialTime); } @@ -187,14 +176,14 @@ contract ValidatorSelectionTest is DecoderBase { } function testValidatorSetLargerThanCommittee(bool _insufficientSigs) public setup(100) { - assertGt(rollup.getAttesters().length, rollup.TARGET_COMMITTEE_SIZE(), "Not enough validators"); - uint256 committeeSize = rollup.TARGET_COMMITTEE_SIZE() * 2 / 3 + (_insufficientSigs ? 0 : 1); + assertGt(rollup.getAttesters().length, rollup.getTargetCommitteeSize(), "Not enough validators"); + uint256 committeeSize = rollup.getTargetCommitteeSize() * 2 / 3 + (_insufficientSigs ? 0 : 1); _testBlock("mixed_block_1", _insufficientSigs, committeeSize, false); assertEq( rollup.getEpochCommittee(rollup.getCurrentEpoch()).length, - rollup.TARGET_COMMITTEE_SIZE(), + rollup.getTargetCommitteeSize(), "Invalid committee size" ); } diff --git a/noir-projects/aztec-nr/.gitrepo b/noir-projects/aztec-nr/.gitrepo index 471aaa39c25..e8a25c97e8f 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = afee26788c91ccfa4a9445f05ada2d20f47d396b + commit = cd752e30f96c006f3e9998b13c1667d4377e2356 method = merge cmdver = 0.4.6 - parent = 9b32585286327c18e809255ad12589daf1cd880b + parent = 73f18a2d85505f2b40b8272a669bcf5772f9133c diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr index ec8c4a2f959..012a0592d2c 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/public_immutable.nr @@ -1,12 +1,19 @@ use crate::{ context::{PrivateContext, PublicContext, UnconstrainedContext}, - history::public_storage::PublicStorageHistoricalRead, state_vars::storage::Storage, + utils::with_hash::WithHash, }; use dep::protocol_types::{constants::INITIALIZATION_SLOT_SEPARATOR, traits::Packable}; /// Stores an immutable value in public state which can be read from public, private and unconstrained execution /// contexts. +/// +/// Leverages `WithHash` to enable efficient private reads of public storage. `WithHash` wrapper allows for +/// efficient reads by verifying large values through a single hash check and then proving inclusion only of the hash +/// in the public storage. This reduces the number of required tree inclusion proofs from O(M) to O(1). +/// +/// This is valuable when T packs to multiple fields, as it maintains "almost constant" verification overhead +/// regardless of the original data size. // docs:start:public_immutable_struct pub struct PublicImmutable { context: Context, @@ -14,9 +21,11 @@ pub struct PublicImmutable { } // docs:end:public_immutable_struct -impl Storage for PublicImmutable +/// `WithHash` stores both the packed value (using N fields) and its hash (1 field), requiring N = M + 1 total +/// fields. +impl Storage for PublicImmutable where - T: Packable, + WithHash: Packable, { fn get_storage_slot(self) -> Field { self.storage_slot @@ -38,7 +47,7 @@ impl PublicImmutable { impl PublicImmutable where - T: Packable, + T: Packable + Eq, { // docs:start:public_immutable_struct_write pub fn initialize(self, value: T) { @@ -49,41 +58,36 @@ where // We populate the initialization slot with a non-zero value to indicate that the struct is initialized self.context.storage_write(initialization_slot, 0xdead); - self.context.storage_write(self.storage_slot, value); + self.context.storage_write(self.storage_slot, WithHash::new(value)); } // docs:end:public_immutable_struct_write // Note that we don't access the context, but we do call oracles that are only available in public // docs:start:public_immutable_struct_read pub fn read(self) -> T { - self.context.storage_read(self.storage_slot) + WithHash::public_storage_read(*self.context, self.storage_slot) } // docs:end:public_immutable_struct_read } impl PublicImmutable where - T: Packable, + T: Packable + Eq, { pub unconstrained fn read(self) -> T { - self.context.storage_read(self.storage_slot) + WithHash::unconstrained_public_storage_read(self.context, self.storage_slot) } } impl PublicImmutable where - T: Packable, + T: Packable + Eq, { pub fn read(self) -> T { - let header = self.context.get_block_header(); - let mut fields = [0; T_PACKED_LEN]; - - for i in 0..fields.len() { - fields[i] = header.public_storage_historical_read( - self.storage_slot + i as Field, - (*self.context).this_address(), - ); - } - T::unpack(fields) + WithHash::historical_public_storage_read( + self.context.get_block_header(), + self.context.this_address(), + self.storage_slot, + ) } } diff --git a/noir-projects/aztec-nr/aztec/src/utils/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/mod.nr index 9cdf9c0125d..8117b646990 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/mod.nr @@ -5,3 +5,4 @@ pub mod field; pub mod point; pub mod to_bytes; pub mod secrets; +pub mod with_hash; diff --git a/noir-projects/aztec-nr/aztec/src/utils/with_hash.nr b/noir-projects/aztec-nr/aztec/src/utils/with_hash.nr new file mode 100644 index 00000000000..c9c9bf95c4f --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/utils/with_hash.nr @@ -0,0 +1,238 @@ +use crate::{ + context::{PublicContext, UnconstrainedContext}, + history::public_storage::PublicStorageHistoricalRead, + oracle, +}; +use dep::protocol_types::{ + address::AztecAddress, block_header::BlockHeader, hash::poseidon2_hash, traits::Packable, +}; + +/// A struct that allows for efficient reading of value `T` from public storage in private. +/// +/// The efficient reads are achieved by verifying large values through a single hash check +/// and then proving inclusion only of the hash in public storage. This reduces the number +/// of required tree inclusion proofs from `N` to 1. +/// +/// # Type Parameters +/// - `T`: The underlying type being wrapped, must implement `Packable` +/// - `N`: The number of field elements required to pack values of type `T` +pub struct WithHash { + value: T, + packed: [Field; N], + hash: Field, +} + +impl WithHash +where + T: Packable + Eq, +{ + pub fn new(value: T) -> Self { + let packed = value.pack(); + Self { value, packed, hash: poseidon2_hash(packed) } + } + + pub fn get_value(self) -> T { + self.value + } + + pub fn get_hash(self) -> Field { + self.hash + } + + pub fn public_storage_read(context: PublicContext, storage_slot: Field) -> T { + context.storage_read(storage_slot) + } + + pub unconstrained fn unconstrained_public_storage_read( + context: UnconstrainedContext, + storage_slot: Field, + ) -> T { + context.storage_read(storage_slot) + } + + pub fn historical_public_storage_read( + header: BlockHeader, + address: AztecAddress, + storage_slot: Field, + ) -> T { + let historical_block_number = header.global_variables.block_number as u32; + + // We could simply produce historical inclusion proofs for each field in `packed`, but that would require one + // full sibling path per storage slot (since due to kernel siloing the storage is not contiguous). Instead, we + // get an oracle to provide us the values, and instead we prove inclusion of their hash, which is both a much + // smaller proof (a single slot), and also independent of the size of T (except in that we need to pack and hash T). + let hint = WithHash::new( + /// Safety: We verify that a hash of the hint/packed data matches the stored hash. + unsafe { + oracle::storage::storage_read(address, storage_slot, historical_block_number) + }, + ); + + let hash = header.public_storage_historical_read(storage_slot + N as Field, address); + + if hash != 0 { + assert_eq(hash, hint.get_hash(), "Hint values do not match hash"); + } else { + // The hash slot can only hold a zero if it is uninitialized. Therefore, the hints must then be zero + // (i.e. the default value for public storage) as well. + assert_eq( + hint.get_value(), + T::unpack(std::mem::zeroed()), + "Non-zero hint for zero hash", + ); + }; + + hint.get_value() + } +} + +impl Packable for WithHash +where + T: Packable, +{ + fn pack(self) -> [Field; N + 1] { + let mut result: [Field; N + 1] = std::mem::zeroed(); + for i in 0..N { + result[i] = self.packed[i]; + } + result[N] = self.hash; + + result + } + + fn unpack(packed: [Field; N + 1]) -> Self { + let mut value_packed: [Field; N] = std::mem::zeroed(); + for i in 0..N { + value_packed[i] = packed[i]; + } + let hash = packed[N]; + + Self { value: T::unpack(value_packed), packed: value_packed, hash } + } +} + +mod test { + use crate::{ + oracle::random::random, + test::{ + helpers::{cheatcodes, test_environment::TestEnvironment}, + mocks::mock_struct::MockStruct, + }, + utils::with_hash::WithHash, + }; + use dep::protocol_types::hash::poseidon2_hash; + use dep::std::{mem, test::OracleMock}; + + global storage_slot: Field = 47; + + #[test] + unconstrained fn create_and_recover() { + let value = MockStruct { a: 5, b: 3 }; + let value_with_hash = WithHash::new(value); + let recovered = WithHash::unpack(value_with_hash.pack()); + + assert_eq(recovered.value, value); + assert_eq(recovered.packed, value.pack()); + assert_eq(recovered.hash, poseidon2_hash(value.pack())); + } + + #[test] + unconstrained fn read_uninitialized_value() { + let mut env = TestEnvironment::new(); + + let block_header = env.private().historical_header; + let address = env.contract_address(); + + let result = WithHash::::historical_public_storage_read( + block_header, + address, + storage_slot, + ); + + // We should get zeroed value + let expected: MockStruct = mem::zeroed(); + assert_eq(result, expected); + } + + #[test] + unconstrained fn read_initialized_value() { + let mut env = TestEnvironment::new(); + + let value = MockStruct { a: 5, b: 3 }; + let value_with_hash = WithHash::new(value); + + // We write the value with hash to storage + cheatcodes::direct_storage_write( + env.contract_address(), + storage_slot, + value_with_hash.pack(), + ); + + // We advance block by 1 because env.private() currently returns context at latest_block - 1 + env.advance_block_by(1); + + let result = WithHash::::historical_public_storage_read( + env.private().historical_header, + env.contract_address(), + storage_slot, + ); + + assert_eq(result, value); + } + + #[test(should_fail_with = "Non-zero hint for zero hash")] + unconstrained fn test_bad_hint_uninitialized_value() { + let mut env = TestEnvironment::new(); + + env.advance_block_to(6); + + let value_packed = MockStruct { a: 1, b: 1 }.pack(); + + let block_header = env.private().historical_header; + let address = env.contract_address(); + + // Mock the oracle to return a non-zero hint/packed value + let _ = OracleMock::mock("storageRead") + .with_params(( + address.to_field(), storage_slot, block_header.global_variables.block_number as u32, + value_packed.len(), + )) + .returns(value_packed) + .times(1); + + // This should revert because the hint value is non-zero and the hash is zero (default value of storage) + let _ = WithHash::::historical_public_storage_read( + block_header, + address, + storage_slot, + ); + } + + #[test(should_fail_with = "Hint values do not match hash")] + unconstrained fn test_bad_hint_initialized_value() { + let mut env = TestEnvironment::new(); + + let value_packed = MockStruct { a: 5, b: 3 }.pack(); + + // We write the value to storage + cheatcodes::direct_storage_write(env.contract_address(), storage_slot, value_packed); + + // Now we write incorrect hash to the hash storage slot + let incorrect_hash = random(); + let hash_storage_slot = storage_slot + (value_packed.len() as Field); + cheatcodes::direct_storage_write( + env.contract_address(), + hash_storage_slot, + [incorrect_hash], + ); + + // We advance block by 1 because env.private() currently returns context at latest_block - 1 + env.advance_block_by(1); + + let _ = WithHash::::historical_public_storage_read( + env.private().historical_header, + env.contract_address(), + storage_slot, + ); + } +} diff --git a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr index 54d21c79a30..6f922cdaa20 100644 --- a/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr +++ b/noir-projects/aztec-nr/compressed-string/src/field_compressed_string.nr @@ -6,7 +6,7 @@ use std::meta::derive; // A Fixedsize Compressed String. // Essentially a special version of Compressed String for practical use. -#[derive(Deserialize, Packable, Serialize)] +#[derive(Deserialize, Eq, Packable, Serialize)] pub struct FieldCompressedString { value: Field, } diff --git a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr index c18136f4412..fe43bb564c3 100644 --- a/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr +++ b/noir-projects/noir-contracts/contracts/amm_contract/src/config.nr @@ -4,7 +4,7 @@ use std::meta::derive; /// We store the tokens of the pool in a struct such that to load it from SharedImmutable asserts only a single /// merkle proof. /// (Once we actually do the optimization. WIP in https://github.com/AztecProtocol/aztec-packages/pull/8022). -#[derive(Deserialize, Packable, Serialize)] +#[derive(Deserialize, Eq, Packable, Serialize)] pub struct Config { pub token0: AztecAddress, pub token1: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 454a0a52b94..3639423f2bd 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -18,6 +18,7 @@ pub contract AppSubscription { use router::utils::privately_check_block_number; use token::Token; + // TODO: This can be optimized by storing the values in Config struct in 1 PublicImmutable (less merkle proofs). #[storage] struct Storage { target_address: PublicImmutable, diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index faa721a531d..c9219815e8a 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -11,6 +11,7 @@ pub contract Claim { use dep::uint_note::uint_note::UintNote; use token::Token; + // TODO: This can be optimized by storing the addresses in Config struct in 1 PublicImmutable (less merkle proofs). #[storage] struct Storage { // Address of a contract based on whose notes we distribute the rewards diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index 4131944789c..bf564557f61 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -31,6 +31,7 @@ pub contract Crowdfunding { amount: U128, } + // TODO: This can be optimized by storing the values in Config struct in 1 PublicImmutable (less merkle proofs). // docs:start:storage #[storage] struct Storage { diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr index b2b352b1986..9e35488bebc 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/leader.nr @@ -2,7 +2,7 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Pa use std::meta::derive; // Shows how to create a custom struct in Public -#[derive(Deserialize, Packable, Serialize)] +#[derive(Deserialize, Eq, Packable, Serialize)] pub struct Leader { account: AztecAddress, points: u8, diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr index cb07cc225f5..fbf1b50eecd 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/config.nr @@ -1,7 +1,7 @@ use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Packable, Serialize}}; use std::meta::derive; -#[derive(Deserialize, Packable, Serialize)] +#[derive(Deserialize, Eq, Packable, Serialize)] pub struct Config { pub accepted_asset: AztecAddress, // Asset the FPC accepts (denoted as AA below) pub admin: AztecAddress, // Address to which AA is sent during the private fee payment flow diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index c36130592c9..1bba78878d6 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -76,7 +76,6 @@ pub contract FPC { // docs:start:fee_entrypoint_private #[private] fn fee_entrypoint_private(max_fee: U128, nonce: Field) { - // TODO(PR #8022): Once PublicImmutable performs only 1 merkle proof here, we'll save ~4k gates let accepted_asset = storage.config.read().accepted_asset; let user = context.msg_sender(); @@ -150,7 +149,6 @@ pub contract FPC { /// 4. The protocol deducts the actual fee denominated in fee juice from the FPC's balance. #[private] fn fee_entrypoint_public(max_fee: U128, nonce: Field) { - // TODO(PR #8022): Once PublicImmutable performs only 1 merkle proof here, we'll save ~4k gates let config = storage.config.read(); // We pull the max fee from the user's balance of the accepted asset to this contract. @@ -198,7 +196,6 @@ pub contract FPC { /// this function. #[public] fn pull_funds(to: AztecAddress) { - // TODO(PR #8022): Once PublicImmutable performs only 1 merkle proof here, we'll save ~4k gates let config = storage.config.read(); assert(context.msg_sender() == config.admin, "Only admin can pull funds"); diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index 1d9c33febf5..a8461de2020 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -14,7 +14,7 @@ pub contract Test { }; use dep::aztec::prelude::{ AztecAddress, EthAddress, FunctionSelector, Map, NoteGetterOptions, NoteViewerOptions, - PrivateImmutable, PrivateSet, + PrivateImmutable, PrivateSet, PublicImmutable, }; use dep::aztec::protocol_types::{ @@ -77,6 +77,7 @@ pub contract Test { example_constant: PrivateImmutable, example_set: PrivateSet, example_struct: PrivateImmutable, + example_struct_in_public_immutable: PublicImmutable, example_struct_in_map: Map, Context>, another_example_struct: PrivateImmutable, } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/test.nr b/noir-projects/noir-contracts/contracts/test_contract/src/test.nr index 346ec5a0fc0..2318510695f 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/test.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/test.nr @@ -25,6 +25,7 @@ unconstrained fn test_storage_slot_allocation() { // example_constant: PrivateImmutable, // example_set: PrivateSet, // example_struct: PrivateImmutable, + // example_struct_in_public_immutable: PublicImmutable, // example_struct_in_map: Map, Context>, // another_example_struct: PrivateImmutable, // } @@ -36,22 +37,27 @@ unconstrained fn test_storage_slot_allocation() { // The first slot is always 1. let mut expected_slot = 1; assert_eq(Test::storage_layout().example_constant.slot, expected_slot); - // Even though example_constant holds TestNote, which packs to a length larger than 1, notes always reserve a // single slot. expected_slot += 1; - assert_eq(Test::storage_layout().example_set.slot, expected_slot); + assert_eq(Test::storage_layout().example_set.slot, expected_slot); // example_set also held a note, so it should have only allocated a single slot. expected_slot += 1; - assert_eq(Test::storage_layout().example_struct.slot, expected_slot); + assert_eq(Test::storage_layout().example_struct.slot, expected_slot); // example_struct allocates 5 slots because it is not a note and it's packed length is 5. expected_slot += 5; - assert_eq(Test::storage_layout().example_struct_in_map.slot, expected_slot); - // example_struct_in_map should allocate a single note because it's a map, regardless of whatever it holds. The Map + assert_eq(Test::storage_layout().example_struct_in_public_immutable.slot, expected_slot); + // example_struct_in_public_immutable should allocate 6 slots because ExampleStruct occupies 5 slots + // and `PublicImmutable` wraps the struct in a `WithHash` that adds an additional slot. + expected_slot += 6; + + assert_eq(Test::storage_layout().example_struct_in_map.slot, expected_slot); + // example_struct_in_map should allocate a single slot because it's a map, regardless of whatever it holds. The Map // type is going to deal with its own dynamic allocation based on keys expected_slot += 1; + assert_eq(Test::storage_layout().another_example_struct.slot, expected_slot); } diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 0f080d3e3e1..b7a4a5919f6 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -24,6 +24,7 @@ pub contract TokenBridge { }; // docs:end:token_bridge_imports + // TODO: This can be optimized by storing the values in Config struct in 1 PublicImmutable (less merkle proofs). // docs:start:token_bridge_storage_and_constructor // Storage structure, containing all storage, and specifying what slots they use. #[storage] diff --git a/noir/bb-version b/noir/bb-version index e40e4fc339c..fac6d18325a 100644 --- a/noir/bb-version +++ b/noir/bb-version @@ -1 +1 @@ -0.66.0 +0.72.1 diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/aztec-nr.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/aztec-nr.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-contracts.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/AztecProtocol/aztec-packages/noir-projects/noir-contracts.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl deleted file mode 100644 index cb56f792778..00000000000 --- a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl +++ /dev/null @@ -1,4 +0,0 @@ -{"event":"started","name":"one","test_count":1,"type":"suite"} -{"event":"started","name":"foo","suite":"one","type":"test"} -{"event":"failed","exec_time":0.05356625,"name":"foo","suite":"one","type":"test"} -{"event":"ok","failed":0,"ignored":0,"passed":1,"type":"suite"} \ No newline at end of file diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq deleted file mode 100644 index 1123e7e68e4..00000000000 --- a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.actual.jsonl.jq +++ /dev/null @@ -1 +0,0 @@ -{"suite":"one","name":"foo"} diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl.jq b/noir/noir-repo/.github/critical_libraries_status/noir-lang/ec/.failures.jsonl.jq deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-edwards/.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir-edwards/.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_bigcurve/.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_bigcurve/.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_json_parser/.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_json_parser/.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_sort/.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/noir-lang/noir_sort/.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/critical_libraries_status/noir-lang/sparse_array/.failures.jsonl.does_not_compile b/noir/noir-repo/.github/critical_libraries_status/noir-lang/sparse_array/.failures.jsonl.does_not_compile deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/noir/noir-repo/.github/workflows/docs-pr.yml b/noir/noir-repo/.github/workflows/docs-pr.yml index 0d47176cc00..c123def6ba3 100644 --- a/noir/noir-repo/.github/workflows/docs-pr.yml +++ b/noir/noir-repo/.github/workflows/docs-pr.yml @@ -2,10 +2,12 @@ name: Deploy preview for PR on: pull_request: + merge_group: jobs: add_label: runs-on: ubuntu-22.04 + if: github.event_name == 'pull_request' outputs: has_label: ${{ steps.check-labels.outputs.result }} steps: diff --git a/noir/noir-repo/.github/workflows/reports.yml b/noir/noir-repo/.github/workflows/reports.yml index 4d8f036a64a..2a1dbc078ac 100644 --- a/noir/noir-repo/.github/workflows/reports.yml +++ b/noir/noir-repo/.github/workflows/reports.yml @@ -76,7 +76,7 @@ jobs: - name: Compare gates reports id: gates_diff - uses: noir-lang/noir-gates-diff@7e4ddaa91c69380f15ccba514eac17bc7432a8cc + uses: noir-lang/noir-gates-diff@dbe920a8dcc3370af4be4f702ca9cef29317bec1 with: report: gates_report.json summaryQuantile: 0.9 # only display the 10% most significant circuit size diffs in the summary (defaults to 20%) @@ -132,7 +132,7 @@ jobs: - name: Compare Brillig bytecode size reports id: brillig_bytecode_diff - uses: noir-lang/noir-gates-diff@7e4ddaa91c69380f15ccba514eac17bc7432a8cc + uses: noir-lang/noir-gates-diff@dbe920a8dcc3370af4be4f702ca9cef29317bec1 with: report: gates_report_brillig.json header: | @@ -192,7 +192,7 @@ jobs: - name: Compare Brillig execution reports id: brillig_execution_diff - uses: noir-lang/noir-gates-diff@c1503343c3e264925ef67c68a2a5eeadd245a77b + uses: noir-lang/noir-gates-diff@dbe920a8dcc3370af4be4f702ca9cef29317bec1 with: report: gates_report_brillig_execution.json header: | @@ -365,10 +365,16 @@ jobs: repository: ${{ matrix.project.repo }} path: test-repo ref: ${{ matrix.project.ref }} + + - name: Fetch noir dependencies + working-directory: ./test-repo/${{ matrix.project.path }} + run: | + # We run `nargo check` to pre-fetch any dependencies so we don't measure the time to download these + # when benchmarking. + nargo check - - name: Generate compilation report without averages + - name: Generate compilation report working-directory: ./test-repo/${{ matrix.project.path }} - if: ${{ !matrix.project.take_average }} run: | mv /home/runner/work/noir/noir/scripts/test_programs/compilation_report.sh ./compilation_report.sh touch parse_time.sh diff --git a/noir/noir-repo/.github/workflows/test-js-packages.yml b/noir/noir-repo/.github/workflows/test-js-packages.yml index b8ba2b679e9..6b40a06e0a2 100644 --- a/noir/noir-repo/.github/workflows/test-js-packages.yml +++ b/noir/noir-repo/.github/workflows/test-js-packages.yml @@ -595,10 +595,23 @@ jobs: sed -i '/^compiler_version/d' ./**/Nargo.toml - name: Run nargo test + id: test_report working-directory: ./test-repo/${{ matrix.project.path }} run: | + output_file=${{ github.workspace }}/noir-repo/.github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.actual.jsonl + BEFORE=$SECONDS nargo test --silence-warnings --skip-brillig-constraints-check --format json ${{ matrix.project.nargo_args }} | tee $output_file + TIME=$(($SECONDS-$BEFORE)) + + NAME=${{ matrix.project.repo }}/${{ matrix.project.path }} + # Replace any slashes with underscores + NAME=${NAME//\//_} + TEST_REPORT_NAME=test_report_$NAME + echo "test_report_name=$TEST_REPORT_NAME" >> $GITHUB_OUTPUT + + jq --null-input "{ test_reports: [{ name: \"$NAME\", value: (\"$TIME\" | tonumber), unit: \"s\" }]}" > $TEST_REPORT_NAME.json + if [ ! -s $output_file ]; then # The file is empty so we delete it to signal that `nargo test` failed before it could run any tests rm -f $output_file @@ -610,6 +623,97 @@ jobs: working-directory: ./noir-repo run: .github/scripts/check_test_results.sh .github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.failures.jsonl .github/critical_libraries_status/${{ matrix.project.repo }}/${{ matrix.project.path }}.actual.jsonl + - name: Upload test report + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.test_report.outputs.test_report_name }} + path: ./test-repo/${{ matrix.project.path }}/${{ steps.test_report.outputs.test_report_name }}.json + retention-days: 3 + overwrite: true + + compile-noir-contracts: + needs: [build-nargo] + runs-on: ubuntu-22.04 + timeout-minutes: 30 + name: Compile `noir-contracts` zero inliner aggressiveness + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + repository: AztecProtocol/aztec-packages + path: test-repo + + - name: Download nargo binary + uses: actions/download-artifact@v4 + with: + name: nargo + path: ./nargo + + - name: Set nargo on PATH + run: | + nargo_binary="${{ github.workspace }}/nargo/nargo" + chmod +x $nargo_binary + echo "$(dirname $nargo_binary)" >> $GITHUB_PATH + export PATH="$PATH:$(dirname $nargo_binary)" + nargo -V + + - name: Remove requirements on compiler version + working-directory: ./test-repo + run: | + # Github actions seems to not expand "**" in globs by default. + shopt -s globstar + sed -i '/^compiler_version/d' ./**/Nargo.toml + + - name: Run nargo compile + working-directory: ./test-repo/noir-projects/noir-contracts + run: nargo compile --inliner-aggressiveness 0 + + upload_critical_library_report: + name: Upload critical library report + needs: [external-repo-checks] + # We want this job to run even if one variation of the matrix in `external-repo-checks` fails + if: always() + runs-on: ubuntu-22.04 + permissions: + pull-requests: write + # deployments permission to deploy GitHub pages website + deployments: write + # contents permission to update benchmark contents in gh-pages branch + contents: write + + steps: + - uses: actions/checkout@v4 + + - name: Download matrix test reports + uses: actions/download-artifact@v4 + with: + pattern: test_report_* + path: ./reports + + - name: Merge test reports using jq + run: | + jq --null-input "{ test_reports: [] }" > test_report.json + mv ./.github/scripts/merge-bench-reports.sh merge-bench-reports.sh + ./merge-bench-reports.sh test_report + jq ".test_reports" < ./test_report.json > test_bench.json + + - name: Store benchmark result + continue-on-error: true + uses: benchmark-action/github-action-benchmark@4de1bed97a47495fc4c5404952da0499e31f5c29 + with: + name: "Test Suite Duration" + tool: "customSmallerIsBetter" + output-file-path: ./test_bench.json + github-token: ${{ secrets.GITHUB_TOKEN }} + # We want this to only run on master to avoid garbage data from PRs being added. + auto-push: ${{ github.ref == 'refs/heads/master' }} + alert-threshold: "120%" + comment-on-alert: true + fail-on-alert: false + alert-comment-cc-users: "@TomAFrench" + max-items-in-chart: 50 + + # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. tests-end: @@ -628,6 +732,7 @@ jobs: - test-integration-node - test-integration-browser - test-examples + - compile-noir-contracts steps: - name: Report overall success diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index f961c452862..7d22780e66a 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -683,9 +683,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitmaps" @@ -854,9 +854,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.9" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -917,9 +917,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", @@ -935,9 +935,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", @@ -947,9 +947,9 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.5.42" +version = "4.5.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0" +checksum = "0952013545c9c6dca60f491602655b795c6c062ab180c9cb0bccb83135461861" dependencies = [ "clap", ] @@ -1160,9 +1160,9 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -1248,9 +1248,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -1943,7 +1943,7 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "ignore", "walkdir", ] @@ -1996,7 +1996,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.7.0", + "indexmap 2.7.1", "slab", "tokio", "tokio-util", @@ -2146,9 +2146,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -2158,9 +2158,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.5.2" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -2462,9 +2462,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -2483,7 +2483,7 @@ dependencies = [ "crossbeam-utils", "dashmap", "env_logger", - "indexmap 2.7.0", + "indexmap 2.7.1", "is-terminal", "itoa", "log", @@ -2525,13 +2525,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2599,9 +2599,9 @@ dependencies = [ [[package]] name = "jsonrpsee" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c71d8c1a731cc4227c2f698d377e7848ca12c8a48866fc5e6951c43a4db843" +checksum = "834af00800e962dee8f7bfc0f60601de215e73e78e5497d733a2919da837d3c8" dependencies = [ "jsonrpsee-core", "jsonrpsee-http-client", @@ -2614,9 +2614,9 @@ dependencies = [ [[package]] name = "jsonrpsee-core" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2882f6f8acb9fdaec7cefc4fd607119a9bd709831df7d7672a1d3b644628280" +checksum = "76637f6294b04e747d68e69336ef839a3493ca62b35bf488ead525f7da75c5bb" dependencies = [ "async-trait", "bytes", @@ -2637,9 +2637,9 @@ dependencies = [ [[package]] name = "jsonrpsee-http-client" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3638bc4617f96675973253b3a45006933bde93c2fd8a6170b33c777cc389e5b" +checksum = "87c24e981ad17798bbca852b0738bfb7b94816ed687bd0d5da60bfa35fa0fdc3" dependencies = [ "async-trait", "base64 0.22.1", @@ -2662,9 +2662,9 @@ dependencies = [ [[package]] name = "jsonrpsee-proc-macros" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06c01ae0007548e73412c08e2285ffe5d723195bf268bce67b1b77c3bb2a14d" +checksum = "6fcae0c6c159e11541080f1f829873d8f374f81eda0abc67695a13fc8dc1a580" dependencies = [ "heck 0.5.0", "proc-macro-crate", @@ -2675,9 +2675,9 @@ dependencies = [ [[package]] name = "jsonrpsee-server" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ad8ddc14be1d4290cd68046e7d1d37acd408efed6d3ca08aefcc3ad6da069c" +checksum = "66b7a3df90a1a60c3ed68e7ca63916b53e9afa928e33531e87f61a9c8e9ae87b" dependencies = [ "futures-util", "http", @@ -2702,9 +2702,9 @@ dependencies = [ [[package]] name = "jsonrpsee-types" -version = "0.24.7" +version = "0.24.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a178c60086f24cc35bb82f57c651d0d25d99c4742b4d335de04e97fa1f08a8a1" +checksum = "ddb81adb1a5ae9182df379e374a79e24e992334e7346af4d065ae5b2acb8d4c6" dependencies = [ "http", "serde", @@ -2794,7 +2794,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "libc", "redox_syscall 0.4.1", ] @@ -2805,7 +2805,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "libc", "redox_syscall 0.5.8", ] @@ -3388,6 +3388,7 @@ dependencies = [ "noirc_frontend", "num-bigint", "num-traits", + "petgraph", "proptest", "rayon", "serde", @@ -3454,7 +3455,7 @@ version = "6.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "crossbeam-channel", "filetime", "fsevent-sys", @@ -3592,9 +3593,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "overload" @@ -3700,7 +3701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.7.0", + "indexmap 2.7.1", ] [[package]] @@ -3948,7 +3949,7 @@ checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.7.0", + "bitflags 2.8.0", "lazy_static", "num-traits", "rand", @@ -4100,7 +4101,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", ] [[package]] @@ -4281,11 +4282,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.43" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -4331,9 +4332,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-platform-verifier" @@ -4427,9 +4428,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "safe-lock" @@ -4534,7 +4535,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "core-foundation", "core-foundation-sys", "libc", @@ -4554,9 +4555,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" @@ -4614,9 +4615,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" dependencies = [ "itoa", "memchr", @@ -4654,7 +4655,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_derive", "serde_json", @@ -4739,9 +4740,9 @@ dependencies = [ [[package]] name = "similar" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" dependencies = [ "bstr", "unicode-segmentation", @@ -4749,9 +4750,9 @@ dependencies = [ [[package]] name = "similar-asserts" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe85670573cd6f0fa97940f26e7e6601213c3b0555246c24234131f88c5709e" +checksum = "9f08357795f0d604ea7d7130f22c74b03838c959bdb14adde3142aab4d18a293" dependencies = [ "console", "similar", @@ -4920,9 +4921,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.13.2" +version = "12.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8150eae9699e3c73a3e6431dc1f80d87748797c0457336af23e94c1de619ed24" +checksum = "13a4dfe4bbeef59c1f32fc7524ae7c95b9e1de5e79a43ce1604e181081d71b0c" dependencies = [ "debugid", "memmap2", @@ -4932,9 +4933,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.13.2" +version = "12.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f4a9846f7a8933b6d198c022faa2c9bd89e1a970bed9d9a98d25708bf8de17" +checksum = "98cf6a95abff97de4d7ff3473f33cacd38f1ddccad5c1feab435d6760300e3b6" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -5257,7 +5258,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "serde", "serde_spanned", "toml_datetime", @@ -5270,9 +5271,9 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.7.1", "toml_datetime", - "winnow 0.6.24", + "winnow 0.6.25", ] [[package]] @@ -5462,9 +5463,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "unicode-linebreak" @@ -5528,15 +5529,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vec-collections" @@ -5913,9 +5914,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.24" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" dependencies = [ "memchr", ] diff --git a/noir/noir-repo/Cargo.toml b/noir/noir-repo/Cargo.toml index 58ca7665c0c..31088d923a4 100644 --- a/noir/noir-repo/Cargo.toml +++ b/noir/noir-repo/Cargo.toml @@ -175,6 +175,7 @@ tracing = "0.1.40" tracing-web = "0.1.3" tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] } rust-embed = "6.6.0" +petgraph = "0.6" [profile.dev] # This is required to be able to run `cargo test` in acvm_js due to the `locals exceeds maximum` error. diff --git a/noir/noir-repo/compiler/noirc_driver/src/lib.rs b/noir/noir-repo/compiler/noirc_driver/src/lib.rs index 9b0172853c0..62186a0c9e8 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/lib.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/lib.rs @@ -135,10 +135,14 @@ pub struct CompileOptions { #[arg(long)] pub skip_underconstrained_check: bool, - /// Flag to turn off the compiler check for missing Brillig call constrains. - /// Warning: This can improve compilation speed but can also lead to correctness errors. + /// Flag to turn on the compiler check for missing Brillig call constraints. + /// Warning: This can degrade compilation speed but will also find some correctness errors. /// This check should always be run on production code. #[arg(long)] + pub enable_brillig_constraints_check: bool, + + /// Hidden Brillig call check flag to maintain CI compatibility (currently ignored) + #[arg(long, hide = true)] pub skip_brillig_constraints_check: bool, /// Setting to decide on an inlining strategy for Brillig functions. @@ -679,7 +683,7 @@ pub fn compile_no_check( }, emit_ssa: if options.emit_ssa { Some(context.package_build_path.clone()) } else { None }, skip_underconstrained_check: options.skip_underconstrained_check, - skip_brillig_constraints_check: options.skip_brillig_constraints_check, + enable_brillig_constraints_check: options.enable_brillig_constraints_check, inliner_aggressiveness: options.inliner_aggressiveness, max_bytecode_increase_percent: options.max_bytecode_increase_percent, }; diff --git a/noir/noir-repo/compiler/noirc_evaluator/Cargo.toml b/noir/noir-repo/compiler/noirc_evaluator/Cargo.toml index 3e30fa6673d..76aa0f50e8a 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/Cargo.toml +++ b/noir/noir-repo/compiler/noirc_evaluator/Cargo.toml @@ -30,6 +30,7 @@ rayon.workspace = true cfg-if.workspace = true smallvec = { version = "1.13.2", features = ["serde"] } vec-collections = "0.4.3" +petgraph.workspace = true [dev-dependencies] proptest.workspace = true diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs index a6117a8f2da..1594bac2acc 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs @@ -58,12 +58,17 @@ pub(crate) fn gen_brillig_for( brillig: &Brillig, ) -> Result, InternalError> { // Create the entry point artifact + let globals_memory_size = brillig + .globals_memory_size + .get(&func.id()) + .copied() + .expect("Should have the globals memory size specified for an entry point"); let mut entry_point = BrilligContext::new_entry_point_artifact( arguments, FunctionContext::return_values(func), func.id(), true, - brillig.globals_memory_size, + globals_memory_size, ); entry_point.name = func.name().to_string(); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 6e406e2b3cb..d2656354b56 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -71,7 +71,10 @@ impl FunctionContext { Type::Slice(_) => { panic!("ICE: Slice parameters cannot be derived from type information") } - _ => unimplemented!("Unsupported function parameter/return type {typ:?}"), + // Treat functions as field values + Type::Function => { + BrilligParameter::SingleAddr(get_bit_size_from_ssa_type(&Type::field())) + } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs index 9f9d271283d..30709f2a6b2 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_globals.rs @@ -1,24 +1,234 @@ +use std::collections::BTreeMap; + use acvm::FieldElement; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; -use super::{BrilligArtifact, BrilligBlock, BrilligVariable, FunctionContext, Label, ValueId}; -use crate::{ - brillig::{brillig_ir::BrilligContext, DataFlowGraph}, - ssa::ir::dfg::GlobalsGraph, +use super::{ + BrilligArtifact, BrilligBlock, BrilligVariable, Function, FunctionContext, Label, ValueId, +}; +use crate::brillig::{ + brillig_ir::BrilligContext, called_functions_vec, Brillig, DataFlowGraph, FunctionId, + Instruction, Value, }; +/// Context structure for generating Brillig globals +/// it stores globals related data required for code generation of regular Brillig functions. +#[derive(Default)] +pub(crate) struct BrilligGlobals { + /// Both `used_globals` and `brillig_entry_points` need to be built + /// from a function call graph. + /// + /// Maps a Brillig function to the globals used in that function. + /// This includes all globals used in functions called internally. + used_globals: HashMap>, + /// Maps a Brillig entry point to all functions called in that entry point. + /// This includes any nested calls as well, as we want to be able to associate + /// any Brillig function with the appropriate global allocations. + brillig_entry_points: HashMap>, + + /// Maps an inner call to its Brillig entry point + /// This is simply used to simplify fetching global allocations when compiling + /// individual Brillig functions. + inner_call_to_entry_point: HashMap>, + /// Final map that associated an entry point with its Brillig global allocations + entry_point_globals_map: HashMap, +} + +/// Mapping of SSA value ids to their Brillig allocations +pub(crate) type SsaToBrilligGlobals = HashMap; + +impl BrilligGlobals { + pub(crate) fn new( + functions: &BTreeMap, + mut used_globals: HashMap>, + main_id: FunctionId, + ) -> Self { + let mut brillig_entry_points = HashMap::default(); + let acir_functions = functions.iter().filter(|(_, func)| func.runtime().is_acir()); + for (_, function) in acir_functions { + for block_id in function.reachable_blocks() { + for instruction_id in function.dfg[block_id].instructions() { + let instruction = &function.dfg[*instruction_id]; + let Instruction::Call { func: func_id, arguments: _ } = instruction else { + continue; + }; + + let func_value = &function.dfg[*func_id]; + let Value::Function(func_id) = func_value else { continue }; + + let called_function = &functions[func_id]; + if called_function.runtime().is_acir() { + continue; + } + + // We have now found a Brillig entry point. + // Let's recursively build a call graph to determine any functions + // whose parent is this entry point and any globals used in those internal calls. + brillig_entry_points.insert(*func_id, HashSet::default()); + Self::mark_entry_points_calls_recursive( + functions, + *func_id, + called_function, + &mut used_globals, + &mut brillig_entry_points, + im::HashSet::new(), + ); + } + } + } + + // If main has been marked as Brillig, it is itself an entry point. + // Run the same analysis from above on main. + let main_func = &functions[&main_id]; + if main_func.runtime().is_brillig() { + brillig_entry_points.insert(main_id, HashSet::default()); + Self::mark_entry_points_calls_recursive( + functions, + main_id, + main_func, + &mut used_globals, + &mut brillig_entry_points, + im::HashSet::new(), + ); + } + + // NB: Temporary fix to override entry point analysis + let merged_set = + used_globals.values().flat_map(|set| set.iter().copied()).collect::>(); + for set in used_globals.values_mut() { + *set = merged_set.clone(); + } + + Self { used_globals, brillig_entry_points, ..Default::default() } + } + + /// Recursively mark any functions called in an entry point as well as + /// any globals used in those functions. + /// Using the information collected we can determine which globals + /// an entry point must initialize. + fn mark_entry_points_calls_recursive( + functions: &BTreeMap, + entry_point: FunctionId, + called_function: &Function, + used_globals: &mut HashMap>, + brillig_entry_points: &mut HashMap>, + mut explored_functions: im::HashSet, + ) { + if explored_functions.insert(called_function.id()).is_some() { + return; + } + + let inner_calls = called_functions_vec(called_function).into_iter().collect::>(); + + for inner_call in inner_calls { + let inner_globals = used_globals + .get(&inner_call) + .expect("Should have a slot for each function") + .clone(); + used_globals + .get_mut(&entry_point) + .expect("ICE: should have func") + .extend(inner_globals); + + if let Some(inner_calls) = brillig_entry_points.get_mut(&entry_point) { + inner_calls.insert(inner_call); + } + + Self::mark_entry_points_calls_recursive( + functions, + entry_point, + &functions[&inner_call], + used_globals, + brillig_entry_points, + explored_functions.clone(), + ); + } + } + + pub(crate) fn declare_globals( + &mut self, + globals_dfg: &DataFlowGraph, + brillig: &mut Brillig, + enable_debug_trace: bool, + ) { + // Map for fetching the correct entry point globals when compiling any function + let mut inner_call_to_entry_point: HashMap> = + HashMap::default(); + let mut entry_point_globals_map = HashMap::default(); + // We only need to generate globals for entry points + for (entry_point, entry_point_inner_calls) in self.brillig_entry_points.iter() { + let entry_point = *entry_point; + + for inner_call in entry_point_inner_calls { + inner_call_to_entry_point.entry(*inner_call).or_default().push(entry_point); + } + + let used_globals = self.used_globals.remove(&entry_point).unwrap_or_default(); + let (artifact, brillig_globals, globals_size) = + convert_ssa_globals(enable_debug_trace, globals_dfg, &used_globals, entry_point); + + entry_point_globals_map.insert(entry_point, brillig_globals); + + brillig.globals.insert(entry_point, artifact); + brillig.globals_memory_size.insert(entry_point, globals_size); + } + + self.inner_call_to_entry_point = inner_call_to_entry_point; + self.entry_point_globals_map = entry_point_globals_map; + } + + /// Fetch the global allocations that can possibly be accessed + /// by any given Brillig function (non-entry point or entry point). + /// The allocations available to a function are determined by its entry point. + /// For a given function id input, this function will search for that function's + /// entry point (or multiple entry points) and fetch the global allocations + /// associated with those entry points. + /// These allocations can then be used when compiling the Brillig function + /// and resolving global variables. + pub(crate) fn get_brillig_globals( + &self, + brillig_function_id: FunctionId, + ) -> SsaToBrilligGlobals { + let entry_points = self.inner_call_to_entry_point.get(&brillig_function_id); + + let mut globals_allocations = HashMap::default(); + if let Some(entry_points) = entry_points { + // A Brillig function is used by multiple entry points. Fetch both globals allocations + // in case one is used by the internal call. + let entry_point_allocations = entry_points + .iter() + .flat_map(|entry_point| self.entry_point_globals_map.get(entry_point)) + .collect::>(); + for map in entry_point_allocations { + globals_allocations.extend(map); + } + } else if let Some(globals) = self.entry_point_globals_map.get(&brillig_function_id) { + // If there is no mapping from an inner call to an entry point, that means `brillig_function_id` + // is itself an entry point and we can fetch the global allocations directly from `self.entry_point_globals_map`. + // vec![globals] + globals_allocations.extend(globals); + } else { + unreachable!( + "ICE: Expected global allocation to be set for function {brillig_function_id}" + ); + } + globals_allocations + } +} + pub(crate) fn convert_ssa_globals( enable_debug_trace: bool, - globals: GlobalsGraph, + globals_dfg: &DataFlowGraph, used_globals: &HashSet, + entry_point: FunctionId, ) -> (BrilligArtifact, HashMap, usize) { - let mut brillig_context = BrilligContext::new_for_global_init(enable_debug_trace); + let mut brillig_context = BrilligContext::new_for_global_init(enable_debug_trace, entry_point); // The global space does not have globals itself let empty_globals = HashMap::default(); // We can use any ID here as this context is only going to be used for globals which does not differentiate // by functions and blocks. The only Label that should be used in the globals context is `Label::globals_init()` let mut function_context = FunctionContext::default(); - brillig_context.enter_context(Label::globals_init()); + brillig_context.enter_context(Label::globals_init(entry_point)); let block_id = DataFlowGraph::default().make_block(); let mut brillig_block = BrilligBlock { @@ -31,13 +241,219 @@ pub(crate) fn convert_ssa_globals( building_globals: true, }; - let globals_dfg = DataFlowGraph::from(globals); - brillig_block.compile_globals(&globals_dfg, used_globals); + brillig_block.compile_globals(globals_dfg, used_globals); - let globals_size = brillig_block.brillig_context.global_space_size(); + let globals_size = brillig_context.global_space_size(); brillig_context.return_instruction(); let artifact = brillig_context.artifact(); (artifact, function_context.ssa_value_allocations, globals_size) } + +#[cfg(test)] +mod tests { + use acvm::{ + acir::brillig::{BitSize, Opcode}, + FieldElement, + }; + + use crate::brillig::{brillig_ir::registers::RegisterAllocator, GlobalSpace, LabelType, Ssa}; + + #[test] + fn entry_points_different_globals() { + let src = " + g0 = Field 2 + + acir(inline) fn main f0 { + b0(v1: Field, v2: Field): + v4 = call f1(v1) -> Field + constrain v4 == Field 2 + v6 = call f2(v1) -> Field + constrain v6 == Field 2 + return + } + brillig(inline) fn entry_point_no_globals f1 { + b0(v1: Field): + v3 = add v1, Field 1 + v4 = add v3, Field 1 + return v4 + } + brillig(inline) fn entry_point_globals f2 { + b0(v1: Field): + v2 = add v1, Field 2 + return v2 + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + // Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation. + let mut ssa = ssa.dead_instruction_elimination(); + + let used_globals_map = std::mem::take(&mut ssa.used_globals); + let brillig = ssa.to_brillig_with_globals(false, used_globals_map); + + assert_eq!( + brillig.globals.len(), + 2, + "Should have a globals artifact associated with each entry point" + ); + for (func_id, mut artifact) in brillig.globals { + let labels = artifact.take_labels(); + // When entering a context two labels are created. + // One is a context label and another is a section label. + assert_eq!(labels.len(), 2); + for (label, position) in labels { + assert_eq!(label.label_type, LabelType::GlobalInit(func_id)); + assert_eq!(position, 0); + } + if func_id.to_u32() == 1 { + assert_eq!( + artifact.byte_code.len(), + 2, + "Expected just a `Return`, but got more than a single opcode" + ); + // assert!(matches!(&artifact.byte_code[0], Opcode::Return)); + } else if func_id.to_u32() == 2 { + assert_eq!( + artifact.byte_code.len(), + 2, + "Expected enough opcodes to initialize the globals" + ); + let Opcode::Const { destination, bit_size, value } = &artifact.byte_code[0] else { + panic!("First opcode is expected to be `Const`"); + }; + assert_eq!(destination.unwrap_direct(), GlobalSpace::start()); + assert!(matches!(bit_size, BitSize::Field)); + assert_eq!(*value, FieldElement::from(2u128)); + + assert!(matches!(&artifact.byte_code[1], Opcode::Return)); + } else { + panic!("Unexpected function id: {func_id}"); + } + } + } + + #[test] + fn entry_point_nested_globals() { + let src = " + g0 = Field 1 + g1 = make_array [Field 1, Field 1] : [Field; 2] + g2 = Field 0 + g3 = make_array [Field 0, Field 0] : [Field; 2] + g4 = make_array [g1, g3] : [[Field; 2]; 2] + + acir(inline) fn main f0 { + b0(v5: Field, v6: Field): + v8 = call f1(v5) -> Field + constrain v8 == Field 2 + call f2(v5, v6) + v12 = call f1(v5) -> Field + constrain v12 == Field 2 + call f3(v5, v6) + v15 = call f1(v5) -> Field + constrain v15 == Field 2 + return + } + brillig(inline) fn entry_point_no_globals f1 { + b0(v5: Field): + v6 = add v5, Field 1 + v7 = add v6, Field 1 + return v7 + } + brillig(inline) fn check_acc_entry_point f2 { + b0(v5: Field, v6: Field): + v8 = allocate -> &mut Field + store Field 0 at v8 + jmp b1(u32 0) + b1(v7: u32): + v11 = lt v7, u32 2 + jmpif v11 then: b3, else: b2 + b2(): + v12 = load v8 -> Field + v13 = eq v12, Field 0 + constrain v13 == u1 0 + v15 = eq v5, v6 + constrain v15 == u1 0 + v16 = add v5, Field 1 + v17 = add v16, Field 1 + constrain v17 == Field 2 + return + b3(): + v19 = array_get g4, index v7 -> [Field; 2] + v20 = load v8 -> Field + v21 = array_get v19, index u32 0 -> Field + v22 = add v20, v21 + v24 = array_get v19, index u32 1 -> Field + v25 = add v22, v24 + store v25 at v8 + v26 = unchecked_add v7, u32 1 + jmp b1(v26) + } + brillig(inline) fn entry_point_inner_func_globals f3 { + b0(v5: Field, v6: Field): + call f4(v5, v6) + return + } + brillig(inline) fn non_entry_point_wrapper f4 { + b0(v5: Field, v6: Field): + call f2(v5, v6) + call f2(v5, v6) + return + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + // Need to run DIE to generate the used globals map, which is necessary for Brillig globals generation. + let mut ssa = ssa.dead_instruction_elimination(); + + let used_globals_map = std::mem::take(&mut ssa.used_globals); + let brillig = ssa.to_brillig_with_globals(false, used_globals_map); + + assert_eq!( + brillig.globals.len(), + 3, + "Should have a globals artifact associated with each entry point" + ); + for (func_id, mut artifact) in brillig.globals { + let labels = artifact.take_labels(); + // When entering a context two labels are created. + // One is a context label and another is a section label. + assert_eq!(labels.len(), 2); + for (label, position) in labels { + assert_eq!(label.label_type, LabelType::GlobalInit(func_id)); + assert_eq!(position, 0); + } + if func_id.to_u32() == 1 { + assert_eq!( + artifact.byte_code.len(), + 30, + "Expected enough opcodes to initialize the globals" + ); + // let Opcode::Const { destination, bit_size, value } = &artifact.byte_code[0] else { + // panic!("First opcode is expected to be `Const`"); + // }; + // assert_eq!(destination.unwrap_direct(), GlobalSpace::start()); + // assert!(matches!(bit_size, BitSize::Field)); + // assert_eq!(*value, FieldElement::from(1u128)); + // assert!(matches!(&artifact.byte_code[1], Opcode::Return)); + } else if func_id.to_u32() == 2 || func_id.to_u32() == 3 { + // We want the entry point which uses globals (f2) and the entry point which calls f2 function internally (f3 through f4) + // to have the same globals initialized. + assert_eq!( + artifact.byte_code.len(), + 30, + "Expected enough opcodes to initialize the globals" + ); + let globals_max_memory = brillig + .globals_memory_size + .get(&func_id) + .copied() + .expect("Should have globals memory size"); + assert_eq!(globals_max_memory, 7); + } else { + panic!("Unexpected function id: {func_id}"); + } + } + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index ad09f73e90f..520fd5aad96 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -37,7 +37,7 @@ use acvm::{ }; use debug_show::DebugShow; -use super::{GlobalSpace, ProcedureId}; +use super::{FunctionId, GlobalSpace, ProcedureId}; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 32 bits. This means that we assume that @@ -221,11 +221,14 @@ impl BrilligContext { /// Special brillig context to codegen global values initialization impl BrilligContext { - pub(crate) fn new_for_global_init(enable_debug_trace: bool) -> BrilligContext { + pub(crate) fn new_for_global_init( + enable_debug_trace: bool, + entry_point: FunctionId, + ) -> BrilligContext { BrilligContext { obj: BrilligArtifact::default(), registers: GlobalSpace::new(), - context_label: Label::globals_init(), + context_label: Label::globals_init(entry_point), current_section: 0, next_section: 1, debug_show: DebugShow::new(enable_debug_trace), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 4c48675d1e7..c9223715042 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -76,7 +76,8 @@ pub(crate) enum LabelType { /// Labels for intrinsic procedures Procedure(ProcedureId), /// Label for initialization of globals - GlobalInit, + /// Stores a function ID referencing the entry point + GlobalInit(FunctionId), } impl std::fmt::Display for LabelType { @@ -91,7 +92,9 @@ impl std::fmt::Display for LabelType { } LabelType::Entrypoint => write!(f, "Entrypoint"), LabelType::Procedure(procedure_id) => write!(f, "Procedure({:?})", procedure_id), - LabelType::GlobalInit => write!(f, "Globals Initialization"), + LabelType::GlobalInit(function_id) => { + write!(f, "Globals Initialization({function_id:?})") + } } } } @@ -127,8 +130,8 @@ impl Label { Label { label_type: LabelType::Procedure(procedure_id), section: None } } - pub(crate) fn globals_init() -> Self { - Label { label_type: LabelType::GlobalInit, section: None } + pub(crate) fn globals_init(function_id: FunctionId) -> Self { + Label { label_type: LabelType::GlobalInit(function_id), section: None } } } @@ -334,4 +337,9 @@ impl BrilligArtifact { pub(crate) fn set_call_stack(&mut self, call_stack: CallStack) { self.call_stack = call_stack; } + + #[cfg(test)] + pub(crate) fn take_labels(&mut self) -> HashMap { + std::mem::take(&mut self.labels) + } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 030ed7133e8..6d4cc814d3e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -32,7 +32,7 @@ impl BrilligContext { context.codegen_entry_point(&arguments, &return_parameters); if globals_init { - context.add_globals_init_instruction(); + context.add_globals_init_instruction(target_function); } context.add_external_call_instruction(target_function); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index d67da423d44..9dd541c7180 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -200,8 +200,8 @@ impl BrilligContext< self.obj.add_unresolved_external_call(BrilligOpcode::Call { location: 0 }, proc_label); } - pub(super) fn add_globals_init_instruction(&mut self) { - let globals_init_label = Label::globals_init(); + pub(super) fn add_globals_init_instruction(&mut self, func_id: FunctionId) { + let globals_init_label = Label::globals_init(func_id); self.debug_show.add_external_call_instruction(globals_init_label.to_string()); self.obj .add_unresolved_external_call(BrilligOpcode::Call { location: 0 }, globals_init_label); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index 88b8a598b10..093c99dec3b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -150,13 +150,14 @@ impl RegisterAllocator for ScratchSpace { /// Globals have a separate memory space /// This memory space is initialized once at the beginning of a program /// and is read-only. +#[derive(Default)] pub(crate) struct GlobalSpace { storage: DeallocationListAllocator, max_memory_address: usize, } impl GlobalSpace { - pub(super) fn new() -> Self { + pub(crate) fn new() -> Self { Self { storage: DeallocationListAllocator::new(Self::start()), max_memory_address: Self::start(), @@ -224,6 +225,7 @@ impl RegisterAllocator for GlobalSpace { } } +#[derive(Default)] struct DeallocationListAllocator { /// A free-list of registers that have been deallocated and can be used again. deallocated_registers: BTreeSet, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs index b74c519f61a..791f6a466cf 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs @@ -2,7 +2,7 @@ pub(crate) mod brillig_gen; pub(crate) mod brillig_ir; use acvm::FieldElement; -use brillig_gen::brillig_globals::convert_ssa_globals; +use brillig_gen::brillig_globals::BrilligGlobals; use brillig_ir::{artifact::LabelType, brillig_variable::BrilligVariable, registers::GlobalSpace}; use self::{ @@ -12,15 +12,18 @@ use self::{ procedures::compile_procedure, }, }; + use crate::ssa::{ ir::{ dfg::DataFlowGraph, function::{Function, FunctionId}, - value::ValueId, + instruction::Instruction, + value::{Value, ValueId}, }, + opt::inlining::called_functions_vec, ssa_gen::Ssa, }; -use fxhash::FxHashMap as HashMap; +use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use std::{borrow::Cow, collections::BTreeSet}; pub use self::brillig_ir::procedures::ProcedureId; @@ -31,8 +34,8 @@ pub use self::brillig_ir::procedures::ProcedureId; pub struct Brillig { /// Maps SSA function labels to their brillig artifact ssa_function_to_brillig: HashMap>, - globals: BrilligArtifact, - globals_memory_size: usize, + globals: HashMap>, + globals_memory_size: HashMap, } impl Brillig { @@ -58,7 +61,7 @@ impl Brillig { } // Procedures are compiled as needed LabelType::Procedure(procedure_id) => Some(Cow::Owned(compile_procedure(procedure_id))), - LabelType::GlobalInit => Some(Cow::Borrowed(&self.globals)), + LabelType::GlobalInit(function_id) => self.globals.get(&function_id).map(Cow::Borrowed), _ => unreachable!("ICE: Expected a function or procedure label"), } } @@ -72,9 +75,18 @@ impl std::ops::Index for Brillig { } impl Ssa { - /// Compile Brillig functions and ACIR functions reachable from them #[tracing::instrument(level = "trace", skip_all)] pub(crate) fn to_brillig(&self, enable_debug_trace: bool) -> Brillig { + self.to_brillig_with_globals(enable_debug_trace, HashMap::default()) + } + + /// Compile Brillig functions and ACIR functions reachable from them + #[tracing::instrument(level = "trace", skip_all)] + pub(crate) fn to_brillig_with_globals( + &self, + enable_debug_trace: bool, + used_globals_map: HashMap>, + ) -> Brillig { // Collect all the function ids that are reachable from brillig // That means all the functions marked as brillig and ACIR functions called by them let brillig_reachable_function_ids = self @@ -89,17 +101,21 @@ impl Ssa { return brillig; } - // Globals are computed once at compile time and shared across all functions, + let mut brillig_globals = + BrilligGlobals::new(&self.functions, used_globals_map, self.main_id); + + // SSA Globals are computed once at compile time and shared across all functions, // thus we can just fetch globals from the main function. + // This same globals graph will then be used to declare Brillig globals for the respective entry points. let globals = (*self.functions[&self.main_id].dfg.globals).clone(); - let (artifact, brillig_globals, globals_size) = - convert_ssa_globals(enable_debug_trace, globals, &self.used_global_values); - brillig.globals = artifact; - brillig.globals_memory_size = globals_size; + let globals_dfg = DataFlowGraph::from(globals); + brillig_globals.declare_globals(&globals_dfg, &mut brillig, enable_debug_trace); for brillig_function_id in brillig_reachable_function_ids { + let globals_allocations = brillig_globals.get_brillig_globals(brillig_function_id); + let func = &self.functions[&brillig_function_id]; - brillig.compile(func, enable_debug_trace, &brillig_globals); + brillig.compile(func, enable_debug_trace, &globals_allocations); } brillig diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs index 3c2857f7399..c17fc2d0b7a 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs @@ -38,7 +38,7 @@ use crate::acir::{Artifacts, GeneratedAcir}; mod checks; pub(super) mod function_builder; pub mod ir; -mod opt; +pub(crate) mod opt; #[cfg(test)] pub(crate) mod parser; pub mod ssa_gen; @@ -68,8 +68,8 @@ pub struct SsaEvaluatorOptions { /// Skip the check for under constrained values pub skip_underconstrained_check: bool, - /// Skip the missing Brillig call constraints check - pub skip_brillig_constraints_check: bool, + /// Enable the missing Brillig call constraints check + pub enable_brillig_constraints_check: bool, /// The higher the value, the more inlined Brillig functions will be. pub inliner_aggressiveness: i64, @@ -112,7 +112,7 @@ pub(crate) fn optimize_into_acir( )); } - if !options.skip_brillig_constraints_check { + if options.enable_brillig_constraints_check { ssa_level_warnings.extend(time( "After Check for Missing Brillig Call Constraints", options.print_codegen_timings, @@ -122,8 +122,9 @@ pub(crate) fn optimize_into_acir( drop(ssa_gen_span_guard); + let used_globals_map = std::mem::take(&mut ssa.used_globals); let brillig = time("SSA to Brillig", options.print_codegen_timings, || { - ssa.to_brillig(options.enable_brillig_logging) + ssa.to_brillig_with_globals(options.enable_brillig_logging, used_globals_map) }); let ssa_gen_span = span!(Level::TRACE, "ssa_generation"); @@ -135,6 +136,9 @@ pub(crate) fn optimize_into_acir( print_codegen_timings: options.print_codegen_timings, } .run_pass(|ssa| ssa.fold_constants_with_brillig(&brillig), "Inlining Brillig Calls Inlining") + // It could happen that we inlined all calls to a given brillig function. + // In that case it's unused so we can remove it. This is what we check next. + .run_pass(Ssa::remove_unreachable_functions, "Removing Unreachable Functions (3rd)") .run_pass(Ssa::dead_instruction_elimination, "Dead Instruction Elimination (2nd)") .finish(); @@ -171,6 +175,7 @@ fn optimize_all(builder: SsaBuilder, options: &SsaEvaluatorOptions) -> Result Result, + purities: Arc, } impl FunctionBuilder { @@ -53,7 +57,6 @@ impl FunctionBuilder { /// right after constructing a new FunctionBuilder. pub(crate) fn new(function_name: String, function_id: FunctionId) -> Self { let new_function = Function::new(function_name, function_id); - Self { current_block: new_function.entry_block(), current_function: new_function, @@ -61,9 +64,22 @@ impl FunctionBuilder { call_stack: CallStackId::root(), error_types: BTreeMap::default(), simplify: true, + globals: Default::default(), + purities: Default::default(), } } + /// Create a function builder with a new function created with the same + /// name, globals, and function purities taken from an existing function. + pub(crate) fn from_existing(function: &Function, function_id: FunctionId) -> Self { + let mut this = Self::new(function.name().to_owned(), function_id); + this.set_globals(function.dfg.globals.clone()); + this.purities = function.dfg.function_purities.clone(); + this.current_function.set_runtime(function.runtime()); + this.current_function.dfg.set_function_purities(this.purities.clone()); + this + } + /// Set the runtime of the initial function that is created internally after constructing /// the FunctionBuilder. A function's default runtime type is `RuntimeType::Acir(InlineType::Inline)`. /// This should only be used immediately following construction of a FunctionBuilder @@ -74,10 +90,20 @@ impl FunctionBuilder { } pub(crate) fn set_globals(&mut self, globals: Arc) { - for (_, value) in globals.values_iter() { + self.globals = globals; + self.apply_globals(); + } + + fn apply_globals(&mut self) { + for (_, value) in self.globals.values_iter() { self.current_function.dfg.make_global(value.get_type().into_owned()); } - self.current_function.set_globals(globals); + self.current_function.set_globals(self.globals.clone()); + } + + pub(crate) fn set_purities(&mut self, purities: Arc) { + self.purities = purities.clone(); + self.current_function.dfg.set_function_purities(purities); } /// Finish the current function and create a new function. @@ -100,6 +126,9 @@ impl FunctionBuilder { self.call_stack = self.current_function.dfg.call_stack_data.get_or_insert_locations(call_stack); self.finished_functions.push(old_function); + + self.current_function.dfg.set_function_purities(self.purities.clone()); + self.apply_globals(); } /// Finish the current function and create a new ACIR function. diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index ad4cd079c3b..aa517d43104 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -1,6 +1,10 @@ use std::{borrow::Cow, sync::Arc}; -use crate::ssa::{function_builder::data_bus::DataBus, ir::instruction::SimplifyResult}; +use crate::ssa::{ + function_builder::data_bus::DataBus, + ir::instruction::SimplifyResult, + opt::pure::{FunctionPurities, Purity}, +}; use super::{ basic_block::{BasicBlock, BasicBlockId}, @@ -104,6 +108,9 @@ pub(crate) struct DataFlowGraph { pub(crate) data_bus: DataBus, pub(crate) globals: Arc, + + #[serde(skip)] + pub(crate) function_purities: Arc, } /// The GlobalsGraph contains the actual global data. @@ -428,7 +435,9 @@ impl DataFlowGraph { if let Some(existing) = self.functions.get(&function) { return *existing; } - self.values.insert(Value::Function(function)) + let result = self.values.insert(Value::Function(function)); + self.functions.insert(function, result); + result } /// Gets or creates a ValueId for the given FunctionId. @@ -436,7 +445,9 @@ impl DataFlowGraph { if let Some(existing) = self.foreign_functions.get(function) { return *existing; } - self.values.insert(Value::ForeignFunction(function.to_owned())) + let result = self.values.insert(Value::ForeignFunction(function.to_owned())); + self.foreign_functions.insert(function.to_owned(), result); + result } /// Gets or creates a ValueId for the given Intrinsic. @@ -757,6 +768,14 @@ impl DataFlowGraph { _ => None, } } + + pub(crate) fn set_function_purities(&mut self, purities: Arc) { + self.function_purities = purities; + } + + pub(crate) fn purity_of(&self, function: FunctionId) -> Option { + self.function_purities.get(&function).copied() + } } impl std::ops::Index for DataFlowGraph { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs index 516cd8e318e..e7748b5f13f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -114,6 +114,7 @@ impl Function { let mut new_function = Function::new(another.name.clone(), id); new_function.set_runtime(another.runtime()); new_function.set_globals(another.dfg.globals.clone()); + new_function.dfg.set_function_purities(another.dfg.function_purities.clone()); new_function } @@ -210,6 +211,16 @@ impl Function { unreachable!("SSA Function {} has no reachable return instruction!", self.id()) } + + pub(crate) fn num_instructions(&self) -> usize { + self.reachable_blocks() + .iter() + .map(|block| { + let block = &self.dfg[*block]; + block.instructions().len() + block.terminator().is_some() as usize + }) + .sum() + } } impl Clone for Function { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 5806e62bf95..a44226096e4 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -10,7 +10,7 @@ use fxhash::FxHasher64; use iter_extended::vecmap; use noirc_frontend::hir_def::types::Type as HirType; -use crate::ssa::opt::flatten_cfg::value_merger::ValueMerger; +use crate::ssa::opt::{flatten_cfg::value_merger::ValueMerger, pure::Purity}; use super::{ basic_block::BasicBlockId, @@ -156,6 +156,14 @@ impl Intrinsic { /// Intrinsics which only have a side effect due to the chance that /// they can fail a constraint can be deduplicated. pub(crate) fn can_be_deduplicated(&self, deduplicate_with_predicate: bool) -> bool { + match self.purity() { + Purity::Pure => true, + Purity::PureWithPredicate => deduplicate_with_predicate, + Purity::Impure => false, + } + } + + pub(crate) fn purity(&self) -> Purity { match self { // These apply a constraint in the form of ACIR opcodes, but they can be deduplicated // if the inputs are the same. If they depend on a side effect variable (e.g. because @@ -170,19 +178,20 @@ impl Intrinsic { BlackBoxFunc::MultiScalarMul | BlackBoxFunc::EmbeddedCurveAdd | BlackBoxFunc::RecursiveAggregation, - ) => deduplicate_with_predicate, + ) => Purity::PureWithPredicate, // Operations that remove items from a slice don't modify the slice, they just assert it's non-empty. Intrinsic::SlicePopBack | Intrinsic::SlicePopFront | Intrinsic::SliceRemove => { - deduplicate_with_predicate + Purity::PureWithPredicate } Intrinsic::AssertConstant | Intrinsic::StaticAssert | Intrinsic::ApplyRangeConstraint - | Intrinsic::AsWitness => deduplicate_with_predicate, + | Intrinsic::AsWitness => Purity::PureWithPredicate, - _ => !self.has_side_effects(), + _ if self.has_side_effects() => Purity::Impure, + _ => Purity::Pure, } } @@ -405,6 +414,9 @@ impl Instruction { Call { func, .. } => match dfg[*func] { Value::Intrinsic(intrinsic) => intrinsic.has_side_effects(), + // Functions known to be pure have no side effects. + // `PureWithPredicates` functions may still have side effects. + Value::Function(function) => dfg.purity_of(function) != Some(Purity::Pure), _ => true, // Be conservative and assume other functions can have side effects. }, @@ -472,6 +484,12 @@ impl Instruction { Value::Intrinsic(intrinsic) => { intrinsic.can_be_deduplicated(deduplicate_with_predicate) } + Value::Function(id) => match function.dfg.purity_of(id) { + Some(Purity::Pure) => true, + Some(Purity::PureWithPredicate) => deduplicate_with_predicate, + Some(Purity::Impure) => false, + None => false, + }, _ => false, }, @@ -605,7 +623,7 @@ impl Instruction { Instruction::EnableSideEffectsIf { .. } | Instruction::ArraySet { .. } => true, Instruction::Call { func, .. } => match dfg[*func] { - Value::Function(_) => true, + Value::Function(id) => !matches!(dfg.purity_of(id), Some(Purity::Pure)), Value::Intrinsic(intrinsic) => { matches!(intrinsic, Intrinsic::SliceInsert | Intrinsic::SliceRemove) } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs index df1e8f537da..cbd1fce406f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs @@ -89,11 +89,14 @@ impl Binary { /// Try to simplify this binary instruction, returning the new value if possible. pub(super) fn simplify(&self, dfg: &mut DataFlowGraph) -> SimplifyResult { - let lhs_value = dfg.get_numeric_constant(self.lhs); - let rhs_value = dfg.get_numeric_constant(self.rhs); + let lhs = dfg.resolve(self.lhs); + let rhs = dfg.resolve(self.rhs); - let lhs_type = dfg.type_of_value(self.lhs).unwrap_numeric(); - let rhs_type = dfg.type_of_value(self.rhs).unwrap_numeric(); + let lhs_value = dfg.get_numeric_constant(lhs); + let rhs_value = dfg.get_numeric_constant(rhs); + + let lhs_type = dfg.type_of_value(lhs).unwrap_numeric(); + let rhs_type = dfg.type_of_value(rhs).unwrap_numeric(); let operator = self.operator; if operator != BinaryOp::Shl && operator != BinaryOp::Shr { @@ -124,7 +127,7 @@ impl Binary { }; // We never return `SimplifyResult::None` here because `operator` might have changed. - let simplified = Instruction::Binary(Binary { lhs: self.lhs, rhs: self.rhs, operator }); + let simplified = Instruction::Binary(Binary { lhs, rhs, operator }); if let (Some(lhs), Some(rhs)) = (lhs_value, rhs_value) { return match eval_constant_binary_op(lhs, rhs, operator, lhs_type) { @@ -145,58 +148,61 @@ impl Binary { match self.operator { BinaryOp::Add { .. } => { if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } } BinaryOp::Sub { .. } => { + if lhs == rhs { + let zero = dfg.make_constant(FieldElement::zero(), lhs_type); + return SimplifyResult::SimplifiedTo(zero); + } + if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } } BinaryOp::Mul { .. } => { if lhs_is_one { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } if lhs_is_zero || rhs_is_zero { let zero = dfg.make_constant(FieldElement::zero(), lhs_type); return SimplifyResult::SimplifiedTo(zero); } - if dfg.get_value_max_num_bits(self.lhs) == 1 { + if dfg.get_value_max_num_bits(lhs) == 1 { // Squaring a boolean value is a noop. - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - return SimplifyResult::SimplifiedTo(self.lhs); + if lhs == rhs { + return SimplifyResult::SimplifiedTo(lhs); } // b*(b*x) = b*x if b is boolean - if let super::Value::Instruction { instruction, .. } = &dfg[self.rhs] { - if let Instruction::Binary(Binary { lhs, rhs, operator }) = + if let super::Value::Instruction { instruction, .. } = &dfg[rhs] { + if let Instruction::Binary(Binary { lhs: b_lhs, rhs: b_rhs, operator }) = dfg[*instruction] { if matches!(operator, BinaryOp::Mul { .. }) - && (dfg.resolve(self.lhs) == dfg.resolve(lhs) - || dfg.resolve(self.lhs) == dfg.resolve(rhs)) + && (lhs == dfg.resolve(b_lhs) || lhs == dfg.resolve(b_rhs)) { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } } } } // (b*x)*b = b*x if b is boolean - if dfg.get_value_max_num_bits(self.rhs) == 1 { - if let super::Value::Instruction { instruction, .. } = &dfg[self.lhs] { - if let Instruction::Binary(Binary { lhs, rhs, operator }) = + if dfg.get_value_max_num_bits(rhs) == 1 { + if let super::Value::Instruction { instruction, .. } = &dfg[lhs] { + if let Instruction::Binary(Binary { lhs: b_lhs, rhs: b_rhs, operator }) = dfg[*instruction] { if matches!(operator, BinaryOp::Mul { .. }) - && (dfg.resolve(self.rhs) == dfg.resolve(lhs) - || dfg.resolve(self.rhs) == dfg.resolve(rhs)) + && (rhs == dfg.resolve(b_lhs) || rhs == dfg.resolve(b_rhs)) { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } } } @@ -204,7 +210,7 @@ impl Binary { } BinaryOp::Div => { if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } } BinaryOp::Mod => { @@ -221,7 +227,7 @@ impl Binary { let bit_size = modulus.ilog2(); return SimplifyResult::SimplifiedToInstruction( Instruction::Truncate { - value: self.lhs, + value: lhs, bit_size, max_bit_size: lhs_type.bit_size(), }, @@ -231,7 +237,7 @@ impl Binary { } } BinaryOp::Eq => { - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + if lhs == rhs { let one = dfg.make_constant(FieldElement::one(), NumericType::bool()); return SimplifyResult::SimplifiedTo(one); } @@ -239,22 +245,22 @@ impl Binary { if lhs_type == NumericType::bool() { // Simplify forms of `(boolean == true)` into `boolean` if lhs_is_one { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } if rhs_is_one { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } // Simplify forms of `(boolean == false)` into `!boolean` if lhs_is_zero { - return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.rhs)); + return SimplifyResult::SimplifiedToInstruction(Instruction::Not(rhs)); } if rhs_is_zero { - return SimplifyResult::SimplifiedToInstruction(Instruction::Not(self.lhs)); + return SimplifyResult::SimplifiedToInstruction(Instruction::Not(lhs)); } } } BinaryOp::Lt => { - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + if lhs == rhs { let zero = dfg.make_constant(FieldElement::zero(), NumericType::bool()); return SimplifyResult::SimplifiedTo(zero); } @@ -267,7 +273,7 @@ impl Binary { let zero = dfg.make_constant(FieldElement::zero(), lhs_type); return SimplifyResult::SimplifiedToInstruction(Instruction::binary( BinaryOp::Eq, - self.lhs, + lhs, zero, )); } @@ -278,14 +284,14 @@ impl Binary { let zero = dfg.make_constant(FieldElement::zero(), lhs_type); return SimplifyResult::SimplifiedTo(zero); } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - return SimplifyResult::SimplifiedTo(self.lhs); + if lhs == rhs { + return SimplifyResult::SimplifiedTo(lhs); } if lhs_type == NumericType::bool() { // Boolean AND is equivalent to multiplication, which is a cheaper operation. // (mul unchecked because these are bools so it doesn't matter really) let instruction = - Instruction::binary(BinaryOp::Mul { unchecked: true }, self.lhs, self.rhs); + Instruction::binary(BinaryOp::Mul { unchecked: true }, lhs, rhs); return SimplifyResult::SimplifiedToInstruction(instruction); } if lhs_type.is_unsigned() { @@ -299,7 +305,7 @@ impl Binary { // The bitmask must then be one less than a power of 2. let bitmask_plus_one = bitmask.to_u128() + 1; if bitmask_plus_one.is_power_of_two() { - let value = if lhs_value.is_some() { self.rhs } else { self.lhs }; + let value = if lhs_value.is_some() { rhs } else { lhs }; let num_bits = bitmask_plus_one.ilog2(); return SimplifyResult::SimplifiedToInstruction( Instruction::Truncate { @@ -317,27 +323,27 @@ impl Binary { } BinaryOp::Or => { if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } if lhs_type == NumericType::bool() && (lhs_is_one || rhs_is_one) { let one = dfg.make_constant(FieldElement::one(), lhs_type); return SimplifyResult::SimplifiedTo(one); } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { - return SimplifyResult::SimplifiedTo(self.lhs); + if lhs == rhs { + return SimplifyResult::SimplifiedTo(lhs); } } BinaryOp::Xor => { if lhs_is_zero { - return SimplifyResult::SimplifiedTo(self.rhs); + return SimplifyResult::SimplifiedTo(rhs); } if rhs_is_zero { - return SimplifyResult::SimplifiedTo(self.lhs); + return SimplifyResult::SimplifiedTo(lhs); } - if dfg.resolve(self.lhs) == dfg.resolve(self.rhs) { + if lhs == rhs { let zero = dfg.make_constant(FieldElement::zero(), lhs_type); return SimplifyResult::SimplifiedTo(zero); } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs index e9c465d264f..d3f8363ba66 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -57,7 +57,12 @@ impl Display for Function { /// Helper function for Function's Display impl to pretty-print the function with the given formatter. fn display_function(function: &Function, f: &mut Formatter) -> Result { - writeln!(f, "{} fn {} {} {{", function.runtime(), function.name(), function.id())?; + if let Some(purity) = function.dfg.purity_of(function.id()) { + writeln!(f, "{} {purity} fn {} {} {{", function.runtime(), function.name(), function.id())?; + } else { + writeln!(f, "{} fn {} {} {{", function.runtime(), function.name(), function.id())?; + } + for block_id in function.reachable_blocks() { display_block(&function.dfg, block_id, f)?; } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index e8cae7da5b5..aea6eda193b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -119,7 +119,9 @@ impl Ssa { let func_value = &function.dfg[*func_id]; let Value::Function(func_id) = func_value else { continue }; - brillig_functions.remove(func_id); + if function.runtime().is_acir() { + brillig_functions.remove(func_id); + } } } } @@ -336,17 +338,22 @@ impl<'brillig> Context<'brillig> { }; // First try to inline a call to a brillig function with all constant arguments. - let new_results = Self::try_inline_brillig_call_with_all_constants( - &instruction, - &old_results, - block, - dfg, - self.brillig_info, - ) - // Otherwise, try inserting the instruction again to apply any optimizations using the newly resolved inputs. - .unwrap_or_else(|| { + let new_results = if runtime_is_brillig { Self::push_instruction(id, instruction.clone(), &old_results, block, dfg) - }); + } else { + // We only want to try to inline Brillig calls for Brillig entry points (functions called from an ACIR runtime). + Self::try_inline_brillig_call_with_all_constants( + &instruction, + &old_results, + block, + dfg, + self.brillig_info, + ) + // Otherwise, try inserting the instruction again to apply any optimizations using the newly resolved inputs. + .unwrap_or_else(|| { + Self::push_instruction(id, instruction.clone(), &old_results, block, dfg) + }) + }; Self::replace_result_ids(dfg, &old_results, &new_results); @@ -404,7 +411,7 @@ impl<'brillig> Context<'brillig> { instruction.map_values_mut(|value_id| { resolve_cache(block, dfg, dom, constraint_simplification_mapping, value_id) }); - instruction + instruction.map_values(|v| dfg.resolve(v)) } /// Pushes a new [`Instruction`] into the [`DataFlowGraph`] which applies any optimizations @@ -718,6 +725,11 @@ impl<'brillig> Context<'brillig> { // Should we consider calls to slice_push_back and similar to be mutating operations as well? if let Store { value: array, .. } | ArraySet { array, .. } = instruction { + if function.dfg.is_global(*array) { + // Early return as we expect globals to be immutable. + return; + }; + let instruction = match &function.dfg[*array] { Value::Instruction { instruction, .. } => &function.dfg[*instruction], _ => return, @@ -764,6 +776,7 @@ impl ResultCache { } } +#[derive(Debug)] enum CacheResult<'a> { Cached(&'a [ValueId]), NeedToHoistToCommonBlock(BasicBlockId), @@ -1333,6 +1346,7 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1361,6 +1375,7 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1389,6 +1404,7 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1418,6 +1434,7 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1447,6 +1464,7 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1481,6 +1499,85 @@ mod test { } "; let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); + assert_normalized_ssa_equals(ssa, expected); + } + + #[test] + fn inlines_brillig_call_with_entry_point_globals() { + let src = " + g0 = Field 2 + + acir(inline) fn main f0 { + b0(): + v1 = call f1() -> Field + return v1 + } + + brillig(inline) fn one f1 { + b0(): + v1 = add g0, Field 3 + return v1 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + let mut ssa = ssa.dead_instruction_elimination(); + let used_globals_map = std::mem::take(&mut ssa.used_globals); + let brillig = ssa.to_brillig_with_globals(false, used_globals_map); + + let expected = " + g0 = Field 2 + + acir(inline) fn main f0 { + b0(): + return Field 5 + } + "; + + let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); + assert_normalized_ssa_equals(ssa, expected); + } + + #[test] + fn inlines_brillig_call_with_non_entry_point_globals() { + let src = " + g0 = Field 2 + + acir(inline) fn main f0 { + b0(): + v1 = call f1() -> Field + return v1 + } + + brillig(inline) fn entry_point f1 { + b0(): + v1 = call f2() -> Field + return v1 + } + + brillig(inline) fn one f2 { + b0(): + v1 = add g0, Field 3 + return v1 + } + "; + let ssa = Ssa::from_str(src).unwrap(); + let mut ssa = ssa.dead_instruction_elimination(); + let used_globals_map = std::mem::take(&mut ssa.used_globals); + let brillig = ssa.to_brillig_with_globals(false, used_globals_map); + + let expected = " + g0 = Field 2 + + acir(inline) fn main f0 { + b0(): + return Field 5 + } + "; + + let ssa = ssa.fold_constants_with_brillig(&brillig); + let ssa = ssa.remove_unreachable_functions(); assert_normalized_ssa_equals(ssa, expected); } @@ -1635,4 +1732,39 @@ mod test { let ssa = ssa.fold_constants_using_constraints(); assert_normalized_ssa_equals(ssa, expected); } + + #[test] + fn pure_call_is_deduplicated() { + let src = " + acir(inline) fn main f0 { + b0(v0: Field): + v1 = call f1(v0) -> Field + v2 = call f1(v0) -> Field + constrain v1 == Field 0 + constrain v2 == Field 0 + return + } + acir(inline) fn foo f1 { + b0(v0: Field): + return v0 + } + "; + + let expected = " + acir(inline) predicate_pure fn main f0 { + b0(v0: Field): + v2 = call f1(v0) -> Field + constrain v2 == Field 0 + return + } + acir(inline) pure fn foo f1 { + b0(v0: Field): + return v0 + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.purity_analysis().fold_constants_using_constraints(); + assert_normalized_ssa_equals(ssa, expected); + } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs index 4afddbef41a..524805238b9 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs @@ -4,7 +4,7 @@ //! with a non-literal target can be replaced with a call to an apply function. //! The apply function is a dispatch function that takes the function id as a parameter //! and dispatches to the correct target. -use std::collections::{BTreeMap, BTreeSet, HashSet}; +use std::collections::{BTreeMap, BTreeSet}; use acvm::FieldElement; use iter_extended::vecmap; @@ -80,21 +80,54 @@ impl DefunctionalizationContext { /// Defunctionalize a single function fn defunctionalize(&mut self, func: &mut Function) { - let mut call_target_values = HashSet::new(); - for block_id in func.reachable_blocks() { - let block = &func.dfg[block_id]; - let instructions = block.instructions().to_vec(); + let block = &mut func.dfg[block_id]; + + // Temporarily take the parameters here just to avoid cloning them + let parameters = block.take_parameters(); + for parameter in ¶meters { + if func.dfg.type_of_value(*parameter) == Type::Function { + func.dfg.set_type_of_value(*parameter, Type::field()); + } + } + + let block = &mut func.dfg[block_id]; + block.set_parameters(parameters); + + // Do the same for the terminator + let mut terminator = block.take_terminator(); + terminator.map_values_mut(|value| map_function_to_field(func, value).unwrap_or(value)); + + let block = &mut func.dfg[block_id]; + block.set_terminator(terminator); - for instruction_id in instructions { - let instruction = func.dfg[instruction_id].clone(); + // Now we can finally change each instruction, replacing + // each first class function with a field value and replacing calls + // to a first class function to a call to the relevant `apply` function. + #[allow(clippy::unnecessary_to_owned)] // clippy is wrong here + for instruction_id in block.instructions().to_vec() { + let mut instruction = func.dfg[instruction_id].clone(); let mut replacement_instruction = None; + + if remove_first_class_functions_in_instruction(func, &mut instruction) { + func.dfg[instruction_id] = instruction.clone(); + } + + #[allow(clippy::unnecessary_to_owned)] // clippy is wrong here + for result in func.dfg.instruction_results(instruction_id).to_vec() { + if func.dfg.type_of_value(result) == Type::Function { + func.dfg.set_type_of_value(result, Type::field()); + } + } + // Operate on call instructions let (target_func_id, arguments) = match &instruction { Instruction::Call { func: target_func_id, arguments } => { (*target_func_id, arguments) } - _ => continue, + _ => { + continue; + } }; match func.dfg[target_func_id] { @@ -116,13 +149,8 @@ impl DefunctionalizationContext { arguments.insert(0, target_func_id); } let func = apply_function_value_id; - call_target_values.insert(func); - replacement_instruction = Some(Instruction::Call { func, arguments }); } - Value::Function(..) => { - call_target_values.insert(target_func_id); - } _ => {} } if let Some(new_instruction) = replacement_instruction { @@ -130,29 +158,6 @@ impl DefunctionalizationContext { } } } - - // Change the type of all the values that are not call targets to NativeField - let value_ids = vecmap(func.dfg.values_iter(), |(id, _)| id); - for value_id in value_ids { - if let Type::Function = func.dfg[value_id].get_type().as_ref() { - match &func.dfg[value_id] { - // If the value is a static function, transform it to the function id - Value::Function(id) => { - if !call_target_values.contains(&value_id) { - let field = NumericType::NativeField; - let new_value = - func.dfg.make_constant(function_id_to_field(*id), field); - func.dfg.set_value_from_id(value_id, new_value); - } - } - // If the value is a function used as value, just change the type of it - Value::Instruction { .. } | Value::Param { .. } => { - func.dfg.set_type_of_value(value_id, Type::field()); - } - _ => {} - } - } - } } /// Returns the apply function for the given signature @@ -161,6 +166,54 @@ impl DefunctionalizationContext { } } +/// Replace any first class functions used in an instruction with a field value. +/// This applies to any function used anywhere else other than the function position +/// of a call instruction. Returns true if the instruction was modified +fn remove_first_class_functions_in_instruction( + func: &mut Function, + instruction: &mut Instruction, +) -> bool { + let mut modified = false; + let mut map_value = |value: ValueId| { + if let Some(new_value) = map_function_to_field(func, value) { + modified = true; + new_value + } else { + value + } + }; + + if let Instruction::Call { func: _, arguments } = instruction { + for arg in arguments { + *arg = map_value(*arg); + } + } else { + instruction.map_values_mut(map_value); + } + + modified +} + +/// Try to map the given function literal to a field, returning Some(field) on success. +/// Returns none if the given value was not a function or doesn't need to be mapped. +fn map_function_to_field(func: &mut Function, value: ValueId) -> Option { + if let Type::Function = func.dfg[value].get_type().as_ref() { + match &func.dfg[value] { + // If the value is a static function, transform it to the function id + Value::Function(id) => { + let new_value = function_id_to_field(*id); + return Some(func.dfg.make_constant(new_value, NumericType::NativeField)); + } + // If the value is a function used as value, just change the type of it + Value::Instruction { .. } | Value::Param { .. } => { + func.dfg.set_type_of_value(value, Type::field()); + } + _ => (), + } + } + None +} + /// Collects all functions used as values that can be called by their signatures fn find_variants(ssa: &Ssa) -> Variants { let mut dynamic_dispatches: BTreeSet<(Signature, RuntimeType)> = BTreeSet::new(); @@ -252,13 +305,25 @@ fn create_apply_functions( variants_map: BTreeMap<(Signature, RuntimeType), Vec>, ) -> ApplyFunctions { let mut apply_functions = HashMap::default(); - for ((signature, runtime), variants) in variants_map.into_iter() { + for ((mut signature, runtime), variants) in variants_map.into_iter() { assert!( !variants.is_empty(), "ICE: at least one variant should exist for a dynamic call {signature:?}" ); let dispatches_to_multiple_functions = variants.len() > 1; + for param in &mut signature.params { + if *param == Type::Function { + *param = Type::field(); + } + } + + for ret in &mut signature.returns { + if *ret == Type::Function { + *ret = Type::field(); + } + } + let id = if dispatches_to_multiple_functions { create_apply_function(ssa, signature.clone(), runtime, variants) } else { @@ -282,10 +347,12 @@ fn create_apply_function( function_ids: Vec, ) -> FunctionId { assert!(!function_ids.is_empty()); - let globals = ssa.functions[&function_ids[0]].dfg.globals.clone(); + let globals = ssa.main().dfg.globals.clone(); + let purities = ssa.main().dfg.function_purities.clone(); ssa.add_fn(|id| { let mut function_builder = FunctionBuilder::new("apply".to_string(), id); function_builder.set_globals(globals); + function_builder.set_purities(purities); // We want to push for apply functions to be inlined more aggressively; // they are expected to be optimized away by constants visible at the call site. @@ -386,10 +453,10 @@ mod tests { v5 = add v0, u32 1 v6 = eq v3, v5 constrain v3 == v5 - v9 = call f1(f3, v0) -> u32 - v10 = add v0, u32 1 - v11 = eq v9, v10 - constrain v9 == v10 + v8 = call f1(f3, v0) -> u32 + v9 = add v0, u32 1 + v10 = eq v8, v9 + constrain v8 == v9 return } brillig(inline) fn wrapper f1 { @@ -419,10 +486,10 @@ mod tests { v5 = add v0, u32 1 v6 = eq v3, v5 constrain v3 == v5 - v9 = call f1(Field 3, v0) -> u32 - v10 = add v0, u32 1 - v11 = eq v9, v10 - constrain v9 == v10 + v8 = call f1(Field 3, v0) -> u32 + v9 = add v0, u32 1 + v10 = eq v8, v9 + constrain v8 == v9 return } brillig(inline) fn wrapper f1 { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs index f02b0975e9d..37cd93ca6af 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -30,26 +30,36 @@ impl Ssa { } fn dead_instruction_elimination_inner(mut self, flattened: bool) -> Ssa { - let mut used_global_values: HashSet<_> = self + let mut used_globals_map: HashMap<_, _> = self .functions .par_iter_mut() - .flat_map(|(_, func)| func.dead_instruction_elimination(true, flattened)) + .filter_map(|(id, func)| { + let set = func.dead_instruction_elimination(true, flattened); + if func.runtime().is_brillig() { + Some((*id, set)) + } else { + None + } + }) .collect(); let globals = &self.functions[&self.main_id].dfg.globals; - // Check which globals are used across all functions - for (id, value) in globals.values_iter().rev() { - if used_global_values.contains(&id) { - if let Value::Instruction { instruction, .. } = &value { - let instruction = &globals[*instruction]; - instruction.for_each_value(|value_id| { - used_global_values.insert(value_id); - }); + for used_global_values in used_globals_map.values_mut() { + // DIE only tracks used instruction results, however, globals include constants. + // Back track globals for internal values which may be in use. + for (id, value) in globals.values_iter().rev() { + if used_global_values.contains(&id) { + if let Value::Instruction { instruction, .. } = &value { + let instruction = &globals[*instruction]; + instruction.for_each_value(|value_id| { + used_global_values.insert(value_id); + }); + } } } } - self.used_global_values = used_global_values; + self.used_globals = used_globals_map; self } @@ -212,7 +222,7 @@ impl Context { .retain(|instruction| !self.instructions_to_remove.contains(instruction)); // Take the mutated array back. - std::mem::swap(&mut self.mutated_array_types, &mut mutated_array_types); + self.mutated_array_types = mutated_array_types; false } @@ -613,13 +623,13 @@ struct RcTracker<'a> { // We also separately track all IncrementRc instructions and all array types which have been mutably borrowed. // If an array is the same type as one of those non-mutated array types, we can safely remove all IncrementRc instructions on that array. inc_rcs: HashMap>, + // Mutated arrays shared across the blocks of the function. + mutated_array_types: &'a mut HashSet, // The SSA often creates patterns where after simplifications we end up with repeat // IncrementRc instructions on the same value. We track whether the previous instruction was an IncrementRc, // and if the current instruction is also an IncrementRc on the same value we remove the current instruction. // `None` if the previous instruction was anything other than an IncrementRc previous_inc_rc: Option, - // Mutated arrays shared across the blocks of the function. - mutated_array_types: &'a mut HashSet, } impl<'a> RcTracker<'a> { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/hint.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/hint.rs index 1326c2cc010..4897799f371 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/hint.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/hint.rs @@ -18,7 +18,7 @@ mod tests { expression_width: ExpressionWidth::default(), emit_ssa: None, skip_underconstrained_check: true, - skip_brillig_constraints_check: true, + enable_brillig_constraints_check: false, inliner_aggressiveness: 0, max_bytecode_increase_percent: None, }; @@ -84,7 +84,7 @@ mod tests { // After Array Set Optimizations: let expected = " - acir(inline) fn main f0 { + acir(inline) impure fn main f0 { b0(v0: u32): constrain u32 50 == v0 v4 = call black_box(u32 10) -> u32 diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs index 7f96df1384b..a8a309a9f12 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs @@ -184,7 +184,7 @@ struct PerFunctionContext<'function> { /// Utility function to find out the direct calls of a function. /// /// Returns the function IDs from all `Call` instructions without deduplication. -fn called_functions_vec(func: &Function) -> Vec { +pub(crate) fn called_functions_vec(func: &Function) -> Vec { let mut called_function_ids = Vec::new(); for block_id in func.reachable_blocks() { for instruction_id in func.dfg[block_id].instructions() { @@ -575,10 +575,7 @@ impl InlineContext { /// that could not be inlined calling it. fn new(ssa: &Ssa, entry_point: FunctionId) -> Self { let source = &ssa.functions[&entry_point]; - let mut builder = FunctionBuilder::new(source.name().to_owned(), entry_point); - builder.set_runtime(source.runtime()); - builder.current_function.set_globals(source.dfg.globals.clone()); - + let builder = FunctionBuilder::from_existing(source, entry_point); Self { builder, recursion_level: 0, entry_point, call_stack: CallStackId::root() } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs index 1e2e783d516..6efed689f51 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/loop_invariant.rs @@ -649,8 +649,8 @@ mod test { v21 = add v1, v2 v23 = array_set v19, index v21, value Field 128 call f1(v23) - v25 = add v2, u32 1 - jmp b1(v25) + v24 = add v2, u32 1 + jmp b1(v24) } brillig(inline) fn foo f1 { b0(v0: [Field; 5]): @@ -685,8 +685,8 @@ mod test { v21 = add v1, v2 v23 = array_set v14, index v21, value Field 128 call f1(v23) - v25 = add v2, u32 1 - jmp b1(v25) + v24 = add v2, u32 1 + jmp b1(v24) } brillig(inline) fn foo f1 { b0(v0: [Field; 5]): diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs index 44796e2531e..7ec419890c0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs @@ -12,12 +12,13 @@ mod defunctionalize; mod die; pub(crate) mod flatten_cfg; mod hint; -mod inlining; +pub(crate) mod inlining; mod loop_invariant; mod make_constrain_not_equal; mod mem2reg; mod normalize_value_ids; mod preprocess_fns; +pub(crate) mod pure; mod rc; mod remove_bit_shifts; mod remove_enable_side_effects; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/pure.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/pure.rs new file mode 100644 index 00000000000..d790d035eb0 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/pure.rs @@ -0,0 +1,367 @@ +use std::collections::BTreeSet; +use std::sync::Arc; + +use fxhash::FxHashMap as HashMap; +use petgraph::prelude::DiGraph; +use petgraph::prelude::NodeIndex as PetGraphIndex; +use petgraph::visit::DfsPostOrder; + +use crate::ssa::{ + ir::{ + function::{Function, FunctionId}, + instruction::{Instruction, TerminatorInstruction}, + value::{Value, ValueId}, + }, + ssa_gen::Ssa, +}; + +impl Ssa { + /// Analyze the purity of each function and tag each function call with that function's purity. + /// This is purely an analysis pass on its own but can help future optimizations. + /// + /// There is no constraint on when this pass needs to be run, but it is generally more + /// beneficial to perform this pass before inlining or loop unrolling so that it can: + /// 1. Run faster by processing fewer instructions. + /// 2. Be run earlier in the pass list so that more passes afterward can use the results of + /// this pass. + /// + /// Performing this pass after defunctionalization may also help more function calls be + /// identified as calling known pure functions. + #[tracing::instrument(level = "trace", skip(self))] + pub(crate) fn purity_analysis(mut self) -> Ssa { + let mut purities = HashMap::default(); + let mut called_functions = HashMap::default(); + + // First look through each function to get a baseline on its purity and collect + // the functions it calls to build a call graph. + for function in self.functions.values() { + let (purity, dependencies) = function.is_pure(); + purities.insert(function.id(), purity); + called_functions.insert(function.id(), dependencies); + } + + // Then transitively 'infect' any functions which call impure functions as also + // impure. + let purities = analyze_call_graph(called_functions, purities, self.main_id); + let purities = Arc::new(purities); + + // We're done, now store purities somewhere every dfg can find it. + for function in self.functions.values_mut() { + function.dfg.set_function_purities(purities.clone()); + } + + self + } +} + +pub(crate) type FunctionPurities = HashMap; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub(crate) enum Purity { + /// Function is completely pure and doesn't rely on a predicate at all. + /// Pure functions can be freely deduplicated or even removed from the program. + Pure, + + /// Function is mostly pure. As long as the predicate is the same. + /// This applies to functions with `constrain` in them. So long as their + /// parameters are the same, the `constrain` should be to the same values + /// so the function is conceptually pure from a deduplication perspective + /// even though it can still interact with the `enable_side_effects`/predicate variable. + /// + /// PureWithPredicate functions can only be deduplicated with identical predicates + /// or a predicate that is a subset of the original. + PureWithPredicate, + + /// This function is impure and cannot be deduplicated even with identical inputs. + /// This is most commonly the case for any function taking or returning a + /// reference value. + Impure, +} + +impl Purity { + /// Unifies two purity values, returning the lower common denominator of the two + pub(crate) fn unify(self, other: Purity) -> Purity { + match (self, other) { + (Purity::Pure, Purity::Pure) => Purity::Pure, + (Purity::Impure, _) | (_, Purity::Impure) => Purity::Impure, + _ => Purity::PureWithPredicate, + } + } +} + +impl std::fmt::Display for Purity { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Purity::Pure => write!(f, "pure"), + Purity::PureWithPredicate => write!(f, "predicate_pure"), + Purity::Impure => write!(f, "impure"), + } + } +} + +impl Function { + fn is_pure(&self) -> (Purity, BTreeSet) { + let contains_reference = |value_id: &ValueId| { + let typ = self.dfg.type_of_value(*value_id); + typ.contains_reference() + }; + + if self.parameters().iter().any(&contains_reference) { + return (Purity::Impure, BTreeSet::new()); + } + + // Set of functions we call which the purity result depends on. + // `is_pure` is intended to be called on each function, building + // up a call graph of sorts to check afterwards to propagate impurity + // from called functions to their callers. Resultingly, an initial "Pure" + // result here could be overridden by one of these dependencies being impure. + let mut dependencies = BTreeSet::new(); + + let mut result = if self.runtime().is_acir() { + Purity::Pure + } else { + // Because we return bogus values when a brillig function is called from acir + // in a disabled predicate, brillig functions can never be truly pure unfortunately. + Purity::PureWithPredicate + }; + + for block in self.reachable_blocks() { + for instruction in self.dfg[block].instructions() { + // We don't defer to Instruction::can_be_deduplicated, Instruction::requires_acir_gen_predicate, + // etc. since we don't consider local mutations to be impure. Local mutations should + // be invisible to calling functions so as long as no references are taken as + // parameters or returned, we can ignore them. + // We even ignore Constrain instructions. As long as the external parameters are + // identical, we should be constraining the same values anyway. + match &self.dfg[*instruction] { + Instruction::Constrain(..) + | Instruction::ConstrainNotEqual(..) + | Instruction::RangeCheck { .. } => { + result = Purity::PureWithPredicate; + } + + // These instructions may be pure unless: + // - We may divide by zero + // - The array index is out of bounds. + // For both cases we can still treat them as pure if the arguments are known + // constants. + ins @ (Instruction::Binary(_) + | Instruction::ArrayGet { .. } + | Instruction::ArraySet { .. }) => { + if ins.requires_acir_gen_predicate(&self.dfg) { + result = Purity::PureWithPredicate; + } + } + Instruction::Call { func, .. } => { + match &self.dfg[*func] { + Value::Function(function_id) => { + // We don't know if this function is pure or not yet, + // so track it as a dependency for now. + dependencies.insert(*function_id); + } + Value::Intrinsic(intrinsic) => match intrinsic.purity() { + Purity::Pure => (), + Purity::PureWithPredicate => result = Purity::PureWithPredicate, + Purity::Impure => return (Purity::Impure, BTreeSet::new()), + }, + Value::ForeignFunction(_) => return (Purity::Impure, BTreeSet::new()), + // The function we're calling is unknown in the remaining cases, + // so just assume the worst. + Value::Global(_) + | Value::Instruction { .. } + | Value::Param { .. } + | Value::NumericConstant { .. } => { + return (Purity::Impure, BTreeSet::new()) + } + } + } + + // The rest are always pure (including allocate, load, & store) + Instruction::Cast(_, _) + | Instruction::Not(_) + | Instruction::Truncate { .. } + | Instruction::Allocate + | Instruction::Load { .. } + | Instruction::Store { .. } + | Instruction::EnableSideEffectsIf { .. } + | Instruction::IncrementRc { .. } + | Instruction::DecrementRc { .. } + | Instruction::IfElse { .. } + | Instruction::MakeArray { .. } + | Instruction::Noop => (), + } + } + + // If the function returns a reference it is impure + let terminator = self.dfg[block].terminator(); + if let Some(TerminatorInstruction::Return { return_values, .. }) = terminator { + if return_values.iter().any(&contains_reference) { + return (Purity::Impure, BTreeSet::new()); + } + } + } + + (result, dependencies) + } +} + +fn analyze_call_graph( + dependencies: HashMap>, + starting_purities: FunctionPurities, + main: FunctionId, +) -> FunctionPurities { + let (graph, ids_to_indices, indices_to_ids) = build_call_graph(dependencies); + + // Now we can analyze it: a function is only as pure as all of + // its called functions + let main_index = ids_to_indices[&main]; + let mut dfs = DfsPostOrder::new(&graph, main_index); + + // The `starting_purities` are the preliminary results from `is_pure` + // that don't take into account function calls. These finished purities do. + let mut finished_purities = HashMap::default(); + + while let Some(index) = dfs.next(&graph) { + let id = indices_to_ids[&index]; + let mut purity = starting_purities[&id]; + + for neighbor_index in graph.neighbors(index) { + let neighbor = indices_to_ids[&neighbor_index]; + + let neighbor_purity = finished_purities.get(&neighbor).copied().unwrap_or({ + // The dependent function isn't finished yet. Since we're following + // calls in a DFS, this means there are mutually recursive functions. + // We could handle these but would need a different, much slower algorithm + // to detect strongly connected components. Instead, since this should be + // a rare case, we bail and assume impure for now. + if neighbor == id { + // If the recursive call is to the same function we can ignore it + purity + } else { + Purity::Impure + } + }); + purity = purity.unify(neighbor_purity); + } + + finished_purities.insert(id, purity); + } + + finished_purities +} + +fn build_call_graph( + dependencies: HashMap>, +) -> (DiGraph, HashMap, HashMap) +{ + let mut graph = DiGraph::new(); + let mut ids_to_indices = HashMap::default(); + let mut indices_to_ids = HashMap::default(); + + for function in dependencies.keys() { + let index = graph.add_node(*function); + ids_to_indices.insert(*function, index); + indices_to_ids.insert(index, *function); + } + + // Create edges from caller -> called + for (function, dependencies) in dependencies { + let function_index = ids_to_indices[&function]; + + for dependency in dependencies { + let dependency_index = ids_to_indices[&dependency]; + graph.add_edge(function_index, dependency_index, ()); + } + } + + (graph, ids_to_indices, indices_to_ids) +} + +#[cfg(test)] +mod test { + use crate::ssa::{ir::function::FunctionId, opt::pure::Purity, ssa_gen::Ssa}; + + #[test] + fn classify_functions() { + let src = " + acir(inline) fn main f0 { + b0(): + v0 = allocate -> &mut Field + call f1(v0) + v1 = call f2() -> &mut Field + call f3(Field 0) + call f4() + call f5() + call f6() + v2 = call f7(u32 2) -> u32 + return + } + + acir(inline) fn impure_take_ref f1 { + b0(v0: &mut Field): + return + } + + acir(inline) fn impure_returns_ref f2 { + b0(): + v0 = allocate -> &mut Field + return v0 + } + + acir(inline) fn predicate_constrain f3 { + b0(v0: Field): + constrain v0 == Field 0 + return + } + + acir(inline) fn predicate_calls_predicate f4 { + b0(): + call f3(Field 0) + return + } + + acir(inline) fn predicate_oob f5 { + b0(): + v0 = make_array [Field 0, Field 1] : [Field; 2] + v1 = array_get v0, index u32 2 -> Field + return + } + + acir(inline) fn pure_basic f6 { + b0(): + v0 = make_array [Field 0, Field 1] : [Field; 2] + v1 = array_get v0, index u32 1 -> Field + v2 = allocate -> &mut Field + store Field 0 at v2 + return + } + + acir(inline) fn pure_recursive f7 { + b0(v0: u32): + v1 = lt v0, u32 1 + jmpif v1 then: b1, else: b2 + b1(): + jmp b3(Field 0) + b2(): + v3 = call f7(v0) -> u32 + call f6() + jmp b3(v3) + b3(v4: u32): + return v4 + } + "; + + let ssa = Ssa::from_str(src).unwrap(); + let ssa = ssa.purity_analysis(); + + let purities = &ssa.main().dfg.function_purities; + assert_eq!(purities[&FunctionId::test_new(0)], Purity::Impure); + assert_eq!(purities[&FunctionId::test_new(1)], Purity::Impure); + assert_eq!(purities[&FunctionId::test_new(2)], Purity::Impure); + assert_eq!(purities[&FunctionId::test_new(3)], Purity::PureWithPredicate); + assert_eq!(purities[&FunctionId::test_new(4)], Purity::PureWithPredicate); + assert_eq!(purities[&FunctionId::test_new(5)], Purity::PureWithPredicate); + assert_eq!(purities[&FunctionId::test_new(6)], Purity::Pure); + assert_eq!(purities[&FunctionId::test_new(7)], Purity::Pure); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index eb0bbd8c532..efdb5f05d32 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -24,10 +24,6 @@ use acvm::{acir::AcirField, FieldElement}; use im::HashSet; use crate::{ - brillig::{ - brillig_gen::{brillig_globals::convert_ssa_globals, convert_ssa_function}, - brillig_ir::brillig_variable::BrilligVariable, - }, errors::RuntimeError, ssa::{ ir::{ @@ -60,8 +56,6 @@ impl Ssa { mut self, max_bytecode_increase_percent: Option, ) -> Result { - let mut global_cache = None; - for function in self.functions.values_mut() { let is_brillig = function.runtime().is_brillig(); @@ -78,19 +72,9 @@ impl Ssa { // to the globals and a mutable reference to the function at the same time, both part of the `Ssa`. if has_unrolled && is_brillig { if let Some(max_incr_pct) = max_bytecode_increase_percent { - if global_cache.is_none() { - let globals = (*function.dfg.globals).clone(); - // DIE is run at the end of our SSA optimizations, so we mark all globals as in use here. - let used_globals = &globals.values_iter().map(|(id, _)| id).collect(); - let (_, brillig_globals, _) = - convert_ssa_globals(false, globals, used_globals); - global_cache = Some(brillig_globals); - } - let brillig_globals = global_cache.as_ref().unwrap(); - let orig_function = orig_function.expect("took snapshot to compare"); - let new_size = brillig_bytecode_size(function, brillig_globals); - let orig_size = brillig_bytecode_size(&orig_function, brillig_globals); + let new_size = function.num_instructions(); + let orig_size = orig_function.num_instructions(); if !is_new_size_ok(orig_size, new_size, max_incr_pct) { *function = orig_function; } @@ -1021,25 +1005,6 @@ fn simplify_between_unrolls(function: &mut Function) { function.mem2reg(); } -/// Convert the function to Brillig bytecode and return the resulting size. -fn brillig_bytecode_size( - function: &Function, - globals: &HashMap, -) -> usize { - // We need to do some SSA passes in order for the conversion to be able to go ahead, - // otherwise we can hit `unreachable!()` instructions in `convert_ssa_instruction`. - // Creating a clone so as not to modify the originals. - let mut temp = function.clone(); - - // Might as well give it the best chance. - simplify_between_unrolls(&mut temp); - - // This is to try to prevent hitting ICE. - temp.dead_instruction_elimination(false, true); - - convert_ssa_function(&temp, false, globals).byte_code.len() -} - /// Decide if the new bytecode size is acceptable, compared to the original. /// /// The maximum increase can be expressed as a negative value if we demand a decrease. diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs index 37d2cd720f9..9fb6f43535c 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/into_ssa.rs @@ -122,6 +122,7 @@ impl Translator { } RuntimeType::Brillig(inline_type) => { self.builder.new_brillig_function(external_name, function_id, inline_type); + self.builder.set_globals(self.globals_graph.clone()); } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/mod.rs index cc660355bbd..fc50bdfba8e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/parser/mod.rs @@ -182,6 +182,10 @@ impl<'a> Parser<'a> { fn parse_function(&mut self) -> ParseResult { let runtime_type = self.parse_runtime_type()?; + + // Ignore function purity if it is in the input + self.eat_identifier().ok(); + self.eat_or_error(Token::Keyword(Keyword::Fn))?; let external_name = self.eat_ident_or_error()?; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index a845c5654b2..f0a52727a7a 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -119,8 +119,8 @@ impl<'a> FunctionContext<'a> { .1; let mut builder = FunctionBuilder::new(function_name, function_id); - builder.set_runtime(runtime); builder.set_globals(Arc::new(globals)); + builder.set_runtime(runtime); let definitions = HashMap::default(); let mut this = Self { definitions, builder, shared_context, loops: Vec::new() }; @@ -136,13 +136,11 @@ impl<'a> FunctionContext<'a> { pub(super) fn new_function(&mut self, id: IrFunctionId, func: &ast::Function) { self.definitions.clear(); - let globals = self.builder.current_function.dfg.globals.clone(); if func.unconstrained { self.builder.new_brillig_function(func.name.clone(), id, func.inline_type); } else { self.builder.new_function(func.name.clone(), id, func.inline_type); } - self.builder.set_globals(globals); self.add_parameters_to_scope(&func.parameters); } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs index 04986bd8db1..ad52473620d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use acvm::acir::circuit::ErrorSelector; -use fxhash::FxHashSet as HashSet; +use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; use iter_extended::btree_map; use serde::{Deserialize, Serialize}; use serde_with::serde_as; @@ -20,7 +20,7 @@ use super::ValueId; pub(crate) struct Ssa { #[serde_as(as = "Vec<(_, _)>")] pub(crate) functions: BTreeMap, - pub(crate) used_global_values: HashSet, + pub(crate) used_globals: HashMap>, pub(crate) main_id: FunctionId, #[serde(skip)] pub(crate) next_id: AtomicCounter, @@ -59,7 +59,7 @@ impl Ssa { error_selector_to_type: error_types, // This field is set only after running DIE and is utilized // for optimizing implementation of globals post-SSA. - used_global_values: HashSet::default(), + used_globals: HashMap::default(), } } diff --git a/noir/noir-repo/compiler/noirc_frontend/Cargo.toml b/noir/noir-repo/compiler/noirc_frontend/Cargo.toml index 041c1b1e015..f9e36f7f3e0 100644 --- a/noir/noir-repo/compiler/noirc_frontend/Cargo.toml +++ b/noir/noir-repo/compiler/noirc_frontend/Cargo.toml @@ -27,7 +27,7 @@ rustc-hash = "1.1.0" small-ord-set = "0.1.3" cfg-if.workspace = true tracing.workspace = true -petgraph = "0.6" +petgraph.workspace = true rangemap = "1.4.0" strum.workspace = true strum_macros.workspace = true diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/enumeration.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/enumeration.rs index eeeb823b9fc..6789a200e6a 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/enumeration.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/enumeration.rs @@ -30,7 +30,11 @@ impl NoirEnumeration { #[derive(Clone, Debug, PartialEq, Eq)] pub struct EnumVariant { pub name: Ident, - pub parameters: Vec, + + /// This is None for tag variants without parameters. + /// A value of `Some(vec![])` corresponds to a variant defined as `Foo()` + /// with parenthesis but no parameters. + pub parameters: Option>, } impl Display for NoirEnumeration { @@ -41,8 +45,12 @@ impl Display for NoirEnumeration { writeln!(f, "enum {}{} {{", self.name, generics)?; for variant in self.variants.iter() { - let parameters = vecmap(&variant.item.parameters, ToString::to_string).join(", "); - writeln!(f, " {}({}),", variant.item.name, parameters)?; + if let Some(parameters) = &variant.item.parameters { + let parameters = vecmap(parameters, ToString::to_string).join(", "); + writeln!(f, " {}({}),", variant.item.name, parameters)?; + } else { + writeln!(f, " {},", variant.item.name)?; + } } write!(f, "}}") diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs index 1f7a37428b2..9c9c0ded867 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs @@ -31,6 +31,7 @@ pub enum ExpressionKind { Cast(Box), Infix(Box), If(Box), + Match(Box), Variable(Path), Tuple(Vec), Lambda(Box), @@ -465,6 +466,12 @@ pub struct IfExpression { pub alternative: Option, } +#[derive(Debug, PartialEq, Eq, Clone)] +pub struct MatchExpression { + pub expression: Expression, + pub rules: Vec<(/*pattern*/ Expression, /*branch*/ Expression)>, +} + #[derive(Debug, PartialEq, Eq, Clone)] pub struct Lambda { pub parameters: Vec<(Pattern, UnresolvedType)>, @@ -612,6 +619,7 @@ impl Display for ExpressionKind { Cast(cast) => cast.fmt(f), Infix(infix) => infix.fmt(f), If(if_expr) => if_expr.fmt(f), + Match(match_expr) => match_expr.fmt(f), Variable(path) => path.fmt(f), Constructor(constructor) => constructor.fmt(f), MemberAccess(access) => access.fmt(f), @@ -739,8 +747,7 @@ impl Display for CastExpression { impl Display for ConstructorExpression { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let fields = - self.fields.iter().map(|(ident, expr)| format!("{ident}: {expr}")).collect::>(); + let fields = vecmap(&self.fields, |(ident, expr)| format!("{ident}: {expr}")); write!(f, "({} {{ {} }})", self.typ, fields.join(", ")) } @@ -791,6 +798,16 @@ impl Display for IfExpression { } } +impl Display for MatchExpression { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "match {} {{", self.expression)?; + for (pattern, branch) in &self.rules { + writeln!(f, " {pattern} -> {branch},")?; + } + write!(f, "}}") + } +} + impl Display for Lambda { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let parameters = vecmap(&self.parameters, |(name, r#type)| format!("{name}: {type}")); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs index d7fe63a6a45..a43bd0a5d3d 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/ast/visitor.rs @@ -22,7 +22,7 @@ use crate::{ use super::{ ForBounds, FunctionReturnType, GenericTypeArgs, IntegerBitSize, ItemVisibility, - NoirEnumeration, Pattern, Signedness, TraitBound, TraitImplItemKind, TypePath, + MatchExpression, NoirEnumeration, Pattern, Signedness, TraitBound, TraitImplItemKind, TypePath, UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, }; @@ -222,6 +222,10 @@ pub trait Visitor { true } + fn visit_match_expression(&mut self, _: &MatchExpression, _: Span) -> bool { + true + } + fn visit_tuple(&mut self, _: &[Expression], _: Span) -> bool { true } @@ -795,8 +799,10 @@ impl NoirEnumeration { } for variant in &self.variants { - for parameter in &variant.item.parameters { - parameter.accept(visitor); + if let Some(parameters) = &variant.item.parameters { + for parameter in parameters { + parameter.accept(visitor); + } } } } @@ -864,6 +870,9 @@ impl Expression { ExpressionKind::If(if_expression) => { if_expression.accept(self.span, visitor); } + ExpressionKind::Match(match_expression) => { + match_expression.accept(self.span, visitor); + } ExpressionKind::Tuple(expressions) => { if visitor.visit_tuple(expressions, self.span) { visit_expressions(expressions, visitor); @@ -1071,6 +1080,22 @@ impl IfExpression { } } +impl MatchExpression { + pub fn accept(&self, span: Span, visitor: &mut impl Visitor) { + if visitor.visit_match_expression(self, span) { + self.accept_children(visitor); + } + } + + pub fn accept_children(&self, visitor: &mut impl Visitor) { + self.expression.accept(visitor); + for (pattern, branch) in &self.rules { + pattern.accept(visitor); + branch.accept(visitor); + } + } +} + impl Lambda { pub fn accept(&self, span: Span, visitor: &mut impl Visitor) { if visitor.visit_lambda(self, span) { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/enums.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/enums.rs index 2ccd2b25561..5153845a57c 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/enums.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/enums.rs @@ -8,7 +8,7 @@ use crate::{ function::{FuncMeta, FunctionBody, HirFunction, Parameters}, stmt::HirPattern, }, - node_interner::{DefinitionKind, FuncId, FunctionModifiers, TypeId}, + node_interner::{DefinitionKind, ExprId, FunctionModifiers, GlobalValue, TypeId}, token::Attributes, DataType, Shared, Type, }; @@ -16,8 +16,96 @@ use crate::{ use super::Elaborator; impl Elaborator<'_> { + /// Defines the value of an enum variant that we resolve an enum + /// variant expression to. E.g. `Foo::Bar` in `Foo::Bar(baz)`. + /// + /// If the variant requires arguments we should define a function, + /// otherwise we define a polymorphic global containing the tag value. #[allow(clippy::too_many_arguments)] - pub(super) fn define_enum_variant_function( + pub(super) fn define_enum_variant_constructor( + &mut self, + enum_: &NoirEnumeration, + type_id: TypeId, + variant: &EnumVariant, + variant_arg_types: Option>, + variant_index: usize, + datatype: &Shared, + self_type: &Type, + self_type_unresolved: UnresolvedType, + ) { + match variant_arg_types { + Some(args) => self.define_enum_variant_function( + enum_, + type_id, + variant, + args, + variant_index, + datatype, + self_type, + self_type_unresolved, + ), + None => self.define_enum_variant_global( + enum_, + type_id, + variant, + variant_index, + datatype, + self_type, + ), + } + } + + #[allow(clippy::too_many_arguments)] + fn define_enum_variant_global( + &mut self, + enum_: &NoirEnumeration, + type_id: TypeId, + variant: &EnumVariant, + variant_index: usize, + datatype: &Shared, + self_type: &Type, + ) { + let name = &variant.name; + let location = Location::new(variant.name.span(), self.file); + + let global_id = self.interner.push_empty_global( + name.clone(), + type_id.local_module_id(), + type_id.krate(), + self.file, + Vec::new(), + false, + false, + ); + + let mut typ = self_type.clone(); + if !datatype.borrow().generics.is_empty() { + let typevars = vecmap(&datatype.borrow().generics, |generic| generic.type_var.clone()); + typ = Type::Forall(typevars, Box::new(typ)); + } + + let definition_id = self.interner.get_global(global_id).definition_id; + self.interner.push_definition_type(definition_id, typ.clone()); + + let no_parameters = Parameters(Vec::new()); + let global_body = + self.make_enum_variant_constructor(datatype, variant_index, &no_parameters, location); + let let_statement = crate::hir_def::stmt::HirStatement::Expression(global_body); + + let statement_id = self.interner.get_global(global_id).let_statement; + self.interner.replace_statement(statement_id, let_statement); + + self.interner.get_global_mut(global_id).value = GlobalValue::Resolved( + crate::hir::comptime::Value::Enum(variant_index, Vec::new(), typ), + ); + + Self::get_module_mut(self.def_maps, type_id.module_id()) + .declare_global(name.clone(), enum_.visibility, global_id) + .ok(); + } + + #[allow(clippy::too_many_arguments)] + fn define_enum_variant_function( &mut self, enum_: &NoirEnumeration, type_id: TypeId, @@ -48,7 +136,10 @@ impl Elaborator<'_> { let hir_name = HirIdent::non_trait_method(definition_id, location); let parameters = self.make_enum_variant_parameters(variant_arg_types, location); - self.push_enum_variant_function_body(id, datatype, variant_index, ¶meters, location); + + let body = + self.make_enum_variant_constructor(datatype, variant_index, ¶meters, location); + self.interner.update_fn(id, HirFunction::unchecked_from_expr(body)); let function_type = datatype_ref.variant_function_type_with_forall(variant_index, datatype.clone()); @@ -106,14 +197,13 @@ impl Elaborator<'_> { // } // } // ``` - fn push_enum_variant_function_body( + fn make_enum_variant_constructor( &mut self, - id: FuncId, self_type: &Shared, variant_index: usize, parameters: &Parameters, location: Location, - ) { + ) -> ExprId { // Each parameter of the enum variant function is used as a parameter of the enum // constructor expression let arguments = vecmap(¶meters.0, |(pattern, typ, _)| match pattern { @@ -126,19 +216,18 @@ impl Elaborator<'_> { _ => unreachable!(), }); - let enum_generics = self_type.borrow().generic_types(); - let construct_variant = HirExpression::EnumConstructor(HirEnumConstructorExpression { + let constructor = HirExpression::EnumConstructor(HirEnumConstructorExpression { r#type: self_type.clone(), - enum_generics: enum_generics.clone(), arguments, variant_index, }); - let body = self.interner.push_expr(construct_variant); - self.interner.update_fn(id, HirFunction::unchecked_from_expr(body)); + let body = self.interner.push_expr(constructor); + let enum_generics = self_type.borrow().generic_types(); let typ = Type::DataType(self_type.clone(), enum_generics); self.interner.push_expr_type(body, typ); self.interner.push_expr_location(body, location.span, location.file); + body } fn make_enum_variant_parameters( diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs index 68e13688b1c..16278995104 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/expressions.rs @@ -7,8 +7,9 @@ use crate::{ ast::{ ArrayLiteral, BlockExpression, CallExpression, CastExpression, ConstructorExpression, Expression, ExpressionKind, Ident, IfExpression, IndexExpression, InfixExpression, - ItemVisibility, Lambda, Literal, MemberAccessExpression, MethodCallExpression, Path, - PrefixExpression, StatementKind, UnaryOp, UnresolvedTypeData, UnresolvedTypeExpression, + ItemVisibility, Lambda, Literal, MatchExpression, MemberAccessExpression, + MethodCallExpression, Path, PathSegment, PrefixExpression, StatementKind, UnaryOp, + UnresolvedTypeData, UnresolvedTypeExpression, }, hir::{ comptime::{self, InterpreterError}, @@ -50,6 +51,7 @@ impl<'context> Elaborator<'context> { ExpressionKind::Cast(cast) => self.elaborate_cast(*cast, expr.span), ExpressionKind::Infix(infix) => return self.elaborate_infix(*infix, expr.span), ExpressionKind::If(if_) => self.elaborate_if(*if_), + ExpressionKind::Match(match_) => self.elaborate_match(*match_), ExpressionKind::Variable(variable) => return self.elaborate_variable(variable), ExpressionKind::Tuple(tuple) => self.elaborate_tuple(tuple), ExpressionKind::Lambda(lambda) => self.elaborate_lambda(*lambda, None), @@ -390,6 +392,7 @@ impl<'context> Elaborator<'context> { fn elaborate_call(&mut self, call: CallExpression, span: Span) -> (HirExpression, Type) { let (func, func_type) = self.elaborate_expression(*call.func); + let func_type = func_type.follow_bindings(); let func_arg_types = if let Type::Function(args, _, _, _) = &func_type { Some(args) } else { None }; @@ -603,6 +606,12 @@ impl<'context> Elaborator<'context> { if let UnresolvedTypeData::Interned(id) = typ { typ = self.interner.get_unresolved_type_data(id).clone(); } + if let UnresolvedTypeData::Resolved(id) = typ { + // If this type is already resolved we can skip the rest of this function + // which just resolves the type, and go straight to resolving the fields. + let resolved = self.interner.get_quoted_type(id).clone(); + return self.elaborate_constructor_with_type(resolved, constructor.fields, span, None); + } let UnresolvedTypeData::Named(mut path, generics, _) = typ else { self.push_err(ResolverError::NonStructUsedInConstructor { typ: typ.to_string(), span }); return (HirExpression::Error, Type::Error); @@ -614,58 +623,78 @@ impl<'context> Elaborator<'context> { } let last_segment = path.last_segment(); - let is_self_type = last_segment.ident.is_self_type_name(); - let (r#type, struct_generics) = if let Some(struct_id) = constructor.struct_type { + let typ = if let Some(struct_id) = constructor.struct_type { let typ = self.interner.get_type(struct_id); let generics = typ.borrow().instantiate(self.interner); - (typ, generics) + Type::DataType(typ, generics) } else { match self.lookup_type_or_error(path) { - Some(Type::DataType(r#type, struct_generics)) if r#type.borrow().is_struct() => { - (r#type, struct_generics) - } - Some(typ) => { - self.push_err(ResolverError::NonStructUsedInConstructor { - typ: typ.to_string(), - span, - }); - return (HirExpression::Error, Type::Error); - } + Some(typ) => typ, None => return (HirExpression::Error, Type::Error), } }; - self.mark_struct_as_constructed(r#type.clone()); + self.elaborate_constructor_with_type(typ, constructor.fields, span, Some(last_segment)) + } - let turbofish_span = last_segment.turbofish_span(); + fn elaborate_constructor_with_type( + &mut self, + typ: Type, + fields: Vec<(Ident, Expression)>, + span: Span, + last_segment: Option, + ) -> (HirExpression, Type) { + let typ = typ.follow_bindings_shallow(); + let (r#type, generics) = match typ.as_ref() { + Type::DataType(r#type, struct_generics) if r#type.borrow().is_struct() => { + (r#type, struct_generics) + } + typ => { + self.push_err(ResolverError::NonStructUsedInConstructor { + typ: typ.to_string(), + span, + }); + return (HirExpression::Error, Type::Error); + } + }; + self.mark_struct_as_constructed(r#type.clone()); - let struct_generics = self.resolve_struct_turbofish_generics( - &r#type.borrow(), - struct_generics, - last_segment.generics, - turbofish_span, - ); + // `last_segment` is optional if this constructor was resolved from a quoted type + let mut generics = generics.clone(); + let mut is_self_type = false; + let mut constructor_type_span = span; + + if let Some(last_segment) = last_segment { + let turbofish_span = last_segment.turbofish_span(); + is_self_type = last_segment.ident.is_self_type_name(); + constructor_type_span = last_segment.ident.span(); + + generics = self.resolve_struct_turbofish_generics( + &r#type.borrow(), + generics, + last_segment.generics, + turbofish_span, + ); + } let struct_type = r#type.clone(); - let generics = struct_generics.clone(); - let fields = constructor.fields; let field_types = r#type .borrow() - .get_fields_with_visibility(&struct_generics) + .get_fields_with_visibility(&generics) .expect("This type should already be validated to be a struct"); let fields = self.resolve_constructor_expr_fields(struct_type.clone(), field_types, fields, span); let expr = HirExpression::Constructor(HirConstructorExpression { fields, - r#type, - struct_generics, + r#type: struct_type.clone(), + struct_generics: generics.clone(), }); let struct_id = struct_type.borrow().id; - let reference_location = Location::new(last_segment.ident.span(), self.file); + let reference_location = Location::new(constructor_type_span, self.file); self.interner.add_type_reference(struct_id, reference_location, is_self_type); (expr, Type::DataType(struct_type, generics)) @@ -898,6 +927,10 @@ impl<'context> Elaborator<'context> { (HirExpression::If(if_expr), ret_type) } + fn elaborate_match(&mut self, _match_expr: MatchExpression) -> (HirExpression, Type) { + (HirExpression::Error, Type::Error) + } + fn elaborate_tuple(&mut self, tuple: Vec) -> (HirExpression, Type) { let mut element_ids = Vec::with_capacity(tuple.len()); let mut element_types = Vec::with_capacity(tuple.len()); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs index 65db9f62559..c895f87ef88 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/elaborator/mod.rs @@ -1841,12 +1841,16 @@ impl<'context> Elaborator<'context> { let module_id = ModuleId { krate: self.crate_id, local_id: typ.module_id }; for (i, variant) in typ.enum_def.variants.iter().enumerate() { - let types = vecmap(&variant.item.parameters, |typ| self.resolve_type(typ.clone())); + let parameters = variant.item.parameters.as_ref(); + let types = + parameters.map(|params| vecmap(params, |typ| self.resolve_type(typ.clone()))); let name = variant.item.name.clone(); - datatype.borrow_mut().push_variant(EnumVariant::new(name, types.clone())); - // Define a function for each variant to construct it - self.define_enum_variant_function( + let is_function = types.is_some(); + let params = types.clone().unwrap_or_default(); + datatype.borrow_mut().push_variant(EnumVariant::new(name, params, is_function)); + + self.define_enum_variant_constructor( &typ.enum_def, *type_id, &variant.item, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs index cbcf8b02d03..1be4bbe61ab 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/display.rs @@ -8,9 +8,9 @@ use crate::{ ArrayLiteral, AsTraitPath, AssignStatement, BlockExpression, CallExpression, CastExpression, ConstrainStatement, ConstructorExpression, Expression, ExpressionKind, ForBounds, ForLoopStatement, ForRange, GenericTypeArgs, IfExpression, IndexExpression, - InfixExpression, LValue, Lambda, LetStatement, Literal, MemberAccessExpression, - MethodCallExpression, Pattern, PrefixExpression, Statement, StatementKind, UnresolvedType, - UnresolvedTypeData, + InfixExpression, LValue, Lambda, LetStatement, Literal, MatchExpression, + MemberAccessExpression, MethodCallExpression, Pattern, PrefixExpression, Statement, + StatementKind, UnresolvedType, UnresolvedTypeData, }, hir_def::traits::TraitConstraint, node_interner::{InternedStatementKind, NodeInterner}, @@ -241,6 +241,7 @@ impl<'interner> TokenPrettyPrinter<'interner> { | Token::GreaterEqual | Token::Equal | Token::NotEqual + | Token::FatArrow | Token::Arrow => write!(f, " {token} "), Token::Assign => { if last_was_op { @@ -365,6 +366,22 @@ impl<'value, 'interner> Display for ValuePrinter<'value, 'interner> { }); write!(f, "{typename} {{ {} }}", fields.join(", ")) } + Value::Enum(tag, args, typ) => { + let args = vecmap(args, |arg| arg.display(self.interner).to_string()).join(", "); + + match typ.follow_bindings_shallow().as_ref() { + Type::DataType(def, _) => { + let def = def.borrow(); + let variant = def.variant_at(*tag); + if variant.is_function { + write!(f, "{}::{}({args})", def.name, variant.name) + } else { + write!(f, "{}::{}", def.name, variant.name) + } + } + other => write!(f, "{other}(args)"), + } + } Value::Pointer(value, _) => write!(f, "&mut {}", value.borrow().display(self.interner)), Value::Array(values, _) => { let values = vecmap(values, |value| value.display(self.interner).to_string()); @@ -586,6 +603,14 @@ fn remove_interned_in_expression_kind( .alternative .map(|alternative| remove_interned_in_expression(interner, alternative)), })), + ExpressionKind::Match(match_expr) => ExpressionKind::Match(Box::new(MatchExpression { + expression: remove_interned_in_expression(interner, match_expr.expression), + rules: vecmap(match_expr.rules, |(pattern, branch)| { + let pattern = remove_interned_in_expression(interner, pattern); + let branch = remove_interned_in_expression(interner, branch); + (pattern, branch) + }), + })), ExpressionKind::Variable(_) => expr, ExpressionKind::Tuple(expressions) => ExpressionKind::Tuple(vecmap(expressions, |expr| { remove_interned_in_expression(interner, expr) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs index e9a615f2c59..0b9c1a5f675 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/errors.rs @@ -133,6 +133,10 @@ pub enum InterpreterError { typ: Type, location: Location, }, + NonEnumInConstructor { + typ: Type, + location: Location, + }, CannotInlineMacro { value: String, typ: Type, @@ -300,6 +304,7 @@ impl InterpreterError { | InterpreterError::CastToNonNumericType { location, .. } | InterpreterError::QuoteInRuntimeCode { location, .. } | InterpreterError::NonStructInConstructor { location, .. } + | InterpreterError::NonEnumInConstructor { location, .. } | InterpreterError::CannotInlineMacro { location, .. } | InterpreterError::UnquoteFoundDuringEvaluation { location, .. } | InterpreterError::UnsupportedTopLevelItemUnquote { location, .. } @@ -505,6 +510,10 @@ impl<'a> From<&'a InterpreterError> for CustomDiagnostic { let msg = format!("`{typ}` is not a struct type"); CustomDiagnostic::simple_error(msg, String::new(), location.span) } + InterpreterError::NonEnumInConstructor { typ, location } => { + let msg = format!("`{typ}` is not an enum type"); + CustomDiagnostic::simple_error(msg, String::new(), location.span) + } InterpreterError::CannotInlineMacro { value, typ, location } => { let msg = format!("Cannot inline values of type `{typ}` into this position"); let secondary = format!("Cannot inline value `{value}`"); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs index 41c75220a3c..33f8e43863e 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter.rs @@ -1290,10 +1290,12 @@ impl<'local, 'interner> Interpreter<'local, 'interner> { fn evaluate_enum_constructor( &mut self, - _constructor: HirEnumConstructorExpression, - _id: ExprId, + constructor: HirEnumConstructorExpression, + id: ExprId, ) -> IResult { - todo!("Support enums in the comptime interpreter") + let fields = try_vecmap(constructor.arguments, |arg| self.evaluate(arg))?; + let typ = self.elaborator.interner.id_type(id).unwrap_forall().1.follow_bindings(); + Ok(Value::Enum(constructor.variant_index, fields, typ)) } fn evaluate_access(&mut self, access: HirMemberAccess, id: ExprId) -> IResult { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 6503b0cf77b..9abb1b190d5 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -246,7 +246,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "unresolved_type_is_bool" => unresolved_type_is_bool(interner, arguments, location), "unresolved_type_is_field" => unresolved_type_is_field(interner, arguments, location), "unresolved_type_is_unit" => unresolved_type_is_unit(interner, arguments, location), - "zeroed" => zeroed(return_type, location.span), + "zeroed" => Ok(zeroed(return_type, location.span)), _ => { let item = format!("Comptime evaluation for builtin function '{name}'"); Err(InterpreterError::Unimplemented { item, location }) @@ -499,21 +499,21 @@ fn struct_def_generics( _ => return Err(InterpreterError::TypeMismatch { expected, actual, location }), }; - let generics: IResult<_> = struct_def + let generics = struct_def .generics .iter() - .map(|generic| -> IResult { + .map(|generic| { let generic_as_named = generic.clone().as_named_generic(); let numeric_type = match generic_as_named.kind() { Kind::Numeric(numeric_type) => Some(Value::Type(*numeric_type)), _ => None, }; - let numeric_type = option(option_typ.clone(), numeric_type, location.span)?; - Ok(Value::Tuple(vec![Value::Type(generic_as_named), numeric_type])) + let numeric_type = option(option_typ.clone(), numeric_type, location.span); + Value::Tuple(vec![Value::Type(generic_as_named), numeric_type]) }) .collect(); - Ok(Value::Slice(generics?, slice_item_type)) + Ok(Value::Slice(generics, slice_item_type)) } fn struct_def_hash(arguments: Vec<(Value, Location)>, location: Location) -> IResult { @@ -811,7 +811,7 @@ fn quoted_as_expr( }, ); - option(return_type, value, location.span) + Ok(option(return_type, value, location.span)) } // fn as_module(quoted: Quoted) -> Option @@ -834,7 +834,7 @@ fn quoted_as_module( module.map(Value::ModuleDefinition) }); - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn as_trait_constraint(quoted: Quoted) -> TraitConstraint @@ -1146,7 +1146,7 @@ where let option_value = f(typ)?; - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn type_eq(_first: Type, _second: Type) -> bool @@ -1181,7 +1181,7 @@ fn type_get_trait_impl( _ => None, }; - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn implements(self, constraint: TraitConstraint) -> bool @@ -1302,7 +1302,7 @@ fn typed_expr_as_function_definition( } else { None }; - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn get_type(self) -> Option @@ -1324,7 +1324,7 @@ fn typed_expr_get_type( } else { None }; - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn as_mutable_reference(self) -> Option @@ -1407,80 +1407,97 @@ where let typ = get_unresolved_type(interner, value)?; let option_value = f(typ); - - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn zeroed() -> T -fn zeroed(return_type: Type, span: Span) -> IResult { +fn zeroed(return_type: Type, span: Span) -> Value { match return_type { - Type::FieldElement => Ok(Value::Field(0u128.into())), + Type::FieldElement => Value::Field(0u128.into()), Type::Array(length_type, elem) => { if let Ok(length) = length_type.evaluate_to_u32(span) { - let element = zeroed(elem.as_ref().clone(), span)?; + let element = zeroed(elem.as_ref().clone(), span); let array = std::iter::repeat(element).take(length as usize).collect(); - Ok(Value::Array(array, Type::Array(length_type, elem))) + Value::Array(array, Type::Array(length_type, elem)) } else { // Assume we can resolve the length later - Ok(Value::Zeroed(Type::Array(length_type, elem))) + Value::Zeroed(Type::Array(length_type, elem)) } } - Type::Slice(_) => Ok(Value::Slice(im::Vector::new(), return_type)), + Type::Slice(_) => Value::Slice(im::Vector::new(), return_type), Type::Integer(sign, bits) => match (sign, bits) { - (Signedness::Unsigned, IntegerBitSize::One) => Ok(Value::U8(0)), - (Signedness::Unsigned, IntegerBitSize::Eight) => Ok(Value::U8(0)), - (Signedness::Unsigned, IntegerBitSize::Sixteen) => Ok(Value::U16(0)), - (Signedness::Unsigned, IntegerBitSize::ThirtyTwo) => Ok(Value::U32(0)), - (Signedness::Unsigned, IntegerBitSize::SixtyFour) => Ok(Value::U64(0)), - (Signedness::Signed, IntegerBitSize::One) => Ok(Value::I8(0)), - (Signedness::Signed, IntegerBitSize::Eight) => Ok(Value::I8(0)), - (Signedness::Signed, IntegerBitSize::Sixteen) => Ok(Value::I16(0)), - (Signedness::Signed, IntegerBitSize::ThirtyTwo) => Ok(Value::I32(0)), - (Signedness::Signed, IntegerBitSize::SixtyFour) => Ok(Value::I64(0)), + (Signedness::Unsigned, IntegerBitSize::One) => Value::U8(0), + (Signedness::Unsigned, IntegerBitSize::Eight) => Value::U8(0), + (Signedness::Unsigned, IntegerBitSize::Sixteen) => Value::U16(0), + (Signedness::Unsigned, IntegerBitSize::ThirtyTwo) => Value::U32(0), + (Signedness::Unsigned, IntegerBitSize::SixtyFour) => Value::U64(0), + (Signedness::Signed, IntegerBitSize::One) => Value::I8(0), + (Signedness::Signed, IntegerBitSize::Eight) => Value::I8(0), + (Signedness::Signed, IntegerBitSize::Sixteen) => Value::I16(0), + (Signedness::Signed, IntegerBitSize::ThirtyTwo) => Value::I32(0), + (Signedness::Signed, IntegerBitSize::SixtyFour) => Value::I64(0), }, - Type::Bool => Ok(Value::Bool(false)), + Type::Bool => Value::Bool(false), Type::String(length_type) => { if let Ok(length) = length_type.evaluate_to_u32(span) { - Ok(Value::String(Rc::new("\0".repeat(length as usize)))) + Value::String(Rc::new("\0".repeat(length as usize))) } else { // Assume we can resolve the length later - Ok(Value::Zeroed(Type::String(length_type))) + Value::Zeroed(Type::String(length_type)) } } Type::FmtString(length_type, captures) => { let length = length_type.evaluate_to_u32(span); let typ = Type::FmtString(length_type, captures); if let Ok(length) = length { - Ok(Value::FormatString(Rc::new("\0".repeat(length as usize)), typ)) + Value::FormatString(Rc::new("\0".repeat(length as usize)), typ) } else { // Assume we can resolve the length later - Ok(Value::Zeroed(typ)) + Value::Zeroed(typ) } } - Type::Unit => Ok(Value::Unit), - Type::Tuple(fields) => Ok(Value::Tuple(try_vecmap(fields, |field| zeroed(field, span))?)), - Type::DataType(struct_type, generics) => { - // TODO: Handle enums - let fields = struct_type.borrow().get_fields(&generics).unwrap(); - let mut values = HashMap::default(); - - for (field_name, field_type) in fields { - let field_value = zeroed(field_type, span)?; - values.insert(Rc::new(field_name), field_value); - } + Type::Unit => Value::Unit, + Type::Tuple(fields) => Value::Tuple(vecmap(fields, |field| zeroed(field, span))), + Type::DataType(data_type, generics) => { + let typ = data_type.borrow(); + + if let Some(fields) = typ.get_fields(&generics) { + let mut values = HashMap::default(); + + for (field_name, field_type) in fields { + let field_value = zeroed(field_type, span); + values.insert(Rc::new(field_name), field_value); + } - let typ = Type::DataType(struct_type, generics); - Ok(Value::Struct(values, typ)) + drop(typ); + Value::Struct(values, Type::DataType(data_type, generics)) + } else if let Some(mut variants) = typ.get_variants(&generics) { + // Since we're defaulting to Vec::new(), this'd allow us to construct 0 element + // variants... `zeroed` is often used for uninitialized values e.g. in a BoundedVec + // though so we'll allow it. + let mut args = Vec::new(); + if !variants.is_empty() { + // is_empty & swap_remove let us avoid a .clone() we'd need if we did .get(0) + let (_name, params) = variants.swap_remove(0); + args = vecmap(params, |param| zeroed(param, span)); + } + + drop(typ); + Value::Enum(0, args, Type::DataType(data_type, generics)) + } else { + drop(typ); + Value::Zeroed(Type::DataType(data_type, generics)) + } } Type::Alias(alias, generics) => zeroed(alias.borrow().get_type(&generics), span), Type::CheckedCast { to, .. } => zeroed(*to, span), typ @ Type::Function(..) => { // Using Value::Zeroed here is probably safer than using FuncId::dummy_id() or similar - Ok(Value::Zeroed(typ)) + Value::Zeroed(typ) } Type::MutableReference(element) => { - let element = zeroed(*element, span)?; - Ok(Value::Pointer(Shared::new(element), false)) + let element = zeroed(*element, span); + Value::Pointer(Shared::new(element), false) } // Optimistically assume we can resolve this type later or that the value is unused Type::TypeVariable(_) @@ -1490,7 +1507,7 @@ fn zeroed(return_type: Type, span: Span) -> IResult { | Type::Quoted(_) | Type::Error | Type::TraitAsType(..) - | Type::NamedGeneric(_, _) => Ok(Value::Zeroed(return_type)), + | Type::NamedGeneric(_, _) => Value::Zeroed(return_type), } } @@ -1543,7 +1560,7 @@ fn expr_as_assert( let option_type = tuple_types.pop().unwrap(); let message = message.map(|msg| Value::expression(msg.kind)); - let message = option(option_type, message, location.span).ok()?; + let message = option(option_type, message, location.span); Some(Value::Tuple(vec![predicate, message])) } else { @@ -1589,7 +1606,7 @@ fn expr_as_assert_eq( let option_type = tuple_types.pop().unwrap(); let message = message.map(|message| Value::expression(message.kind)); - let message = option(option_type, message, location.span).ok()?; + let message = option(option_type, message, location.span); Some(Value::Tuple(vec![lhs, rhs, message])) } else { @@ -1765,7 +1782,7 @@ fn expr_as_constructor( None }; - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn as_for(self) -> Option<(Quoted, Expr, Expr)> @@ -1865,7 +1882,7 @@ fn expr_as_if( Some(Value::Tuple(vec![ Value::expression(if_expr.condition.kind), Value::expression(if_expr.consequence.kind), - alternative.ok()?, + alternative, ])) } else { None @@ -1948,7 +1965,7 @@ fn expr_as_lambda( } else { Some(Value::UnresolvedType(typ.typ)) }; - let typ = option(option_unresolved_type.clone(), typ, location.span).unwrap(); + let typ = option(option_unresolved_type.clone(), typ, location.span); Value::Tuple(vec![pattern, typ]) }) .collect(); @@ -1967,7 +1984,7 @@ fn expr_as_lambda( Some(return_type) }; let return_type = return_type.map(Value::UnresolvedType); - let return_type = option(option_unresolved_type, return_type, location.span).ok()?; + let return_type = option(option_unresolved_type, return_type, location.span); let body = Value::expression(lambda.body.kind); @@ -2001,7 +2018,7 @@ fn expr_as_let( Some(Value::UnresolvedType(let_statement.r#type.typ)) }; - let typ = option(option_type, typ, location.span).ok()?; + let typ = option(option_type, typ, location.span); Some(Value::Tuple(vec![ Value::pattern(let_statement.pattern), @@ -2253,7 +2270,7 @@ where let expr_value = unwrap_expr_value(interner, expr_value); let option_value = f(expr_value); - option(return_type, option_value, location.span) + Ok(option(return_type, option_value, location.span)) } // fn resolve(self, in_function: Option) -> TypedExpr @@ -2902,18 +2919,18 @@ fn trait_def_as_trait_constraint( /// Creates a value that holds an `Option`. /// `option_type` must be a Type referencing the `Option` type. -pub(crate) fn option(option_type: Type, value: Option, span: Span) -> IResult { +pub(crate) fn option(option_type: Type, value: Option, span: Span) -> Value { let t = extract_option_generic_type(option_type.clone()); let (is_some, value) = match value { Some(value) => (Value::Bool(true), value), - None => (Value::Bool(false), zeroed(t, span)?), + None => (Value::Bool(false), zeroed(t, span)), }; let mut fields = HashMap::default(); fields.insert(Rc::new("_is_some".to_string()), is_some); fields.insert(Rc::new("_value".to_string()), value); - Ok(Value::Struct(fields, option_type)) + Value::Struct(fields, option_type) } /// Given a type, assert that it's an Option and return the Type for T diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs index c5ec7d861cd..c1a831c70a8 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/comptime/value.rs @@ -15,8 +15,8 @@ use crate::{ elaborator::Elaborator, hir::{def_map::ModuleId, type_check::generics::TraitGenerics}, hir_def::expr::{ - HirArrayLiteral, HirConstructorExpression, HirExpression, HirIdent, HirLambda, HirLiteral, - ImplKind, + HirArrayLiteral, HirConstructorExpression, HirEnumConstructorExpression, HirExpression, + HirIdent, HirLambda, HirLiteral, ImplKind, }, node_interner::{ExprId, FuncId, NodeInterner, StmtId, TraitId, TraitImplId, TypeId}, parser::{Item, Parser}, @@ -55,6 +55,7 @@ pub enum Value { Tuple(Vec), Struct(HashMap, Value>, Type), + Enum(/*tag*/ usize, /*args*/ Vec, Type), Pointer(Shared, /* auto_deref */ bool), Array(Vector, Type), Slice(Vector, Type), @@ -131,6 +132,7 @@ impl Value { Type::Tuple(vecmap(fields, |field| field.get_type().into_owned())) } Value::Struct(_, typ) => return Cow::Borrowed(typ), + Value::Enum(_, _, typ) => return Cow::Borrowed(typ), Value::Array(_, typ) => return Cow::Borrowed(typ), Value::Slice(_, typ) => return Cow::Borrowed(typ), Value::Quoted(_) => Type::Quoted(QuotedType::Quoted), @@ -233,7 +235,7 @@ impl Value { Ok((Ident::new(unwrap_rc(name), location.span), field)) })?; - let struct_type = match typ.follow_bindings() { + let struct_type = match typ.follow_bindings_shallow().as_ref() { Type::DataType(def, _) => Some(def.borrow().id), _ => return Err(InterpreterError::NonStructInConstructor { typ, location }), }; @@ -246,6 +248,10 @@ impl Value { struct_type, })) } + value @ Value::Enum(..) => { + let hir = value.into_hir_expression(elaborator.interner, location)?; + ExpressionKind::Resolved(hir) + } Value::Array(elements, _) => { let elements = try_vecmap(elements, |element| element.into_expression(elaborator, location))?; @@ -398,6 +404,22 @@ impl Value { fields, }) } + Value::Enum(variant_index, args, typ) => { + // Enum constants can have generic types but aren't functions + let r#type = match typ.unwrap_forall().1.follow_bindings() { + Type::DataType(def, _) => def, + _ => return Err(InterpreterError::NonEnumInConstructor { typ, location }), + }; + + let arguments = + try_vecmap(args, |arg| arg.into_hir_expression(interner, location))?; + + HirExpression::EnumConstructor(HirEnumConstructorExpression { + r#type, + variant_index, + arguments, + }) + } Value::Array(elements, _) => { let elements = try_vecmap(elements, |element| { element.into_hir_expression(interner, location) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs index 9aad806bb3c..73c6c5a5dd2 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs @@ -161,6 +161,7 @@ impl CollectedItems { pub fn is_empty(&self) -> bool { self.functions.is_empty() && self.structs.is_empty() + && self.enums.is_empty() && self.type_aliases.is_empty() && self.traits.is_empty() && self.globals.is_empty() diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs index fea52be88bc..e85fa629d56 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs @@ -54,11 +54,11 @@ pub struct Context<'file_manager, 'parsed_files> { pub package_build_path: PathBuf, } -#[derive(Debug, Copy, Clone)] -pub enum FunctionNameMatch<'a> { +#[derive(Debug)] +pub enum FunctionNameMatch { Anything, - Exact(&'a str), - Contains(&'a str), + Exact(Vec), + Contains(Vec), } impl Context<'_, '_> { @@ -175,7 +175,7 @@ impl Context<'_, '_> { pub fn get_all_test_functions_in_crate_matching( &self, crate_id: &CrateId, - pattern: FunctionNameMatch, + pattern: &FunctionNameMatch, ) -> Vec<(String, TestFunction)> { let interner = &self.def_interner; let def_map = self.def_map(crate_id).expect("The local crate should be analyzed already"); @@ -187,10 +187,13 @@ impl Context<'_, '_> { self.fully_qualified_function_name(crate_id, &test_function.get_id()); match &pattern { FunctionNameMatch::Anything => Some((fully_qualified_name, test_function)), - FunctionNameMatch::Exact(pattern) => (&fully_qualified_name == pattern) + FunctionNameMatch::Exact(patterns) => patterns + .iter() + .any(|pattern| &fully_qualified_name == pattern) .then_some((fully_qualified_name, test_function)), - FunctionNameMatch::Contains(pattern) => fully_qualified_name - .contains(pattern) + FunctionNameMatch::Contains(patterns) => patterns + .iter() + .any(|pattern| fully_qualified_name.contains(pattern)) .then_some((fully_qualified_name, test_function)), } }) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs index 647969471ab..00b94411fcd 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs @@ -297,7 +297,6 @@ pub struct HirConstructorExpression { #[derive(Debug, Clone)] pub struct HirEnumConstructorExpression { pub r#type: Shared, - pub enum_generics: Vec, pub variant_index: usize, /// This refers to just the arguments that are passed. E.g. just diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs index 1a9241b3b46..a79af9a7630 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs @@ -368,11 +368,16 @@ pub struct StructField { pub struct EnumVariant { pub name: Ident, pub params: Vec, + + /// True if this variant was declared as a function. + /// Required to distinguish `Foo::Bar` from `Foo::Bar()` + /// for zero-parameter variants. Only required for printing. + pub is_function: bool, } impl EnumVariant { - pub fn new(name: Ident, params: Vec) -> EnumVariant { - Self { name, params } + pub fn new(name: Ident, params: Vec, is_function: bool) -> EnumVariant { + Self { name, params, is_function } } } @@ -1737,6 +1742,13 @@ impl Type { ) -> Result<(), UnificationError> { use Type::*; + // If the two types are exactly the same then they trivially unify. + // This check avoids potentially unifying very complex types (usually infix + // expressions) when they are the same. + if self == other { + return Ok(()); + } + let lhs = self.follow_bindings_shallow(); let rhs = other.follow_bindings_shallow(); diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs index 5750365c62d..ce9125cd5f0 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types/arithmetic.rs @@ -63,12 +63,15 @@ impl Type { let dummy_span = Span::default(); // evaluate_to_field_element also calls canonicalize so if we just called // `self.evaluate_to_field_element(..)` we'd get infinite recursion. - if let (Ok(lhs_value), Ok(rhs_value)) = ( - lhs.evaluate_to_field_element_helper(&kind, dummy_span, run_simplifications), - rhs.evaluate_to_field_element_helper(&kind, dummy_span, run_simplifications), - ) { - if let Ok(result) = op.function(lhs_value, rhs_value, &kind, dummy_span) { - return Type::Constant(result, kind); + if let Ok(lhs_value) = + lhs.evaluate_to_field_element_helper(&kind, dummy_span, run_simplifications) + { + if let Ok(rhs_value) = + rhs.evaluate_to_field_element_helper(&kind, dummy_span, run_simplifications) + { + if let Ok(result) = op.function(lhs_value, rhs_value, &kind, dummy_span) { + return Type::Constant(result, kind); + } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs index 0b7bd0991d9..771af3daba0 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs @@ -215,8 +215,19 @@ impl<'a> Lexer<'a> { Ok(prev_token.into_single_span(start)) } } + Token::Assign => { + let start = self.position; + if self.peek_char_is('=') { + self.next_char(); + Ok(Token::Equal.into_span(start, start + 1)) + } else if self.peek_char_is('>') { + self.next_char(); + Ok(Token::FatArrow.into_span(start, start + 1)) + } else { + Ok(prev_token.into_single_span(start)) + } + } Token::Bang => self.single_double_peek_token('=', prev_token, Token::NotEqual), - Token::Assign => self.single_double_peek_token('=', prev_token, Token::Equal), Token::Minus => self.single_double_peek_token('>', prev_token, Token::Arrow), Token::Colon => self.single_double_peek_token(':', prev_token, Token::DoubleColon), Token::Slash => { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs index 7d11b97ca16..d0a6f05e05a 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -91,6 +91,8 @@ pub enum BorrowedToken<'input> { RightBracket, /// -> Arrow, + /// => + FatArrow, /// | Pipe, /// # @@ -212,6 +214,8 @@ pub enum Token { RightBracket, /// -> Arrow, + /// => + FatArrow, /// | Pipe, /// # @@ -296,6 +300,7 @@ pub fn token_to_borrowed_token(token: &Token) -> BorrowedToken<'_> { Token::LeftBracket => BorrowedToken::LeftBracket, Token::RightBracket => BorrowedToken::RightBracket, Token::Arrow => BorrowedToken::Arrow, + Token::FatArrow => BorrowedToken::FatArrow, Token::Pipe => BorrowedToken::Pipe, Token::Pound => BorrowedToken::Pound, Token::Comma => BorrowedToken::Comma, @@ -473,6 +478,7 @@ impl fmt::Display for Token { Token::LeftBracket => write!(f, "["), Token::RightBracket => write!(f, "]"), Token::Arrow => write!(f, "->"), + Token::FatArrow => write!(f, "=>"), Token::Pipe => write!(f, "|"), Token::Pound => write!(f, "#"), Token::Comma => write!(f, ","), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs index de8e4f6f864..7ad703523d4 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs @@ -777,13 +777,12 @@ impl<'interner> Monomorphizer<'interner> { } /// For an enum like: - /// ``` /// enum Foo { /// A(i32, u32), /// B(Field), /// C /// } - /// ``` + /// /// this will translate the call `Foo::A(1, 2)` into `(0, (1, 2), (0,), ())` where /// the first field `0` is the tag value, the second is `A`, third is `B`, and fourth is `C`. /// Each variant that isn't the desired variant has zeroed values filled in for its data. @@ -2210,7 +2209,7 @@ fn unwrap_enum_type( typ: &HirType, location: Location, ) -> Result)>, MonomorphizationError> { - match typ.follow_bindings() { + match typ.unwrap_forall().1.follow_bindings() { HirType::DataType(def, args) => { // Some of args might not be mentioned in fields, so we need to check that they aren't unbound. for arg in &args { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/enums.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/enums.rs index f95c0f8f72b..3b496a438cf 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/enums.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/enums.rs @@ -92,12 +92,10 @@ impl<'a> Parser<'a> { self.bump(); } - let mut parameters = Vec::new(); - - if self.eat_left_paren() { + let parameters = self.eat_left_paren().then(|| { let comma_separated = separated_by_comma_until_right_paren(); - parameters = self.parse_many("variant parameters", comma_separated, Self::parse_type); - } + self.parse_many("variant parameters", comma_separated, Self::parse_type) + }); Some(Documented::new(EnumVariant { name, parameters }, doc_comments)) } @@ -189,18 +187,19 @@ mod tests { let variant = noir_enum.variants.remove(0).item; assert_eq!("X", variant.name.to_string()); assert!(matches!( - variant.parameters[0].typ, + variant.parameters.as_ref().unwrap()[0].typ, UnresolvedTypeData::Integer(Signedness::Signed, IntegerBitSize::ThirtyTwo) )); let variant = noir_enum.variants.remove(0).item; assert_eq!("y", variant.name.to_string()); - assert!(matches!(variant.parameters[0].typ, UnresolvedTypeData::FieldElement)); - assert!(matches!(variant.parameters[1].typ, UnresolvedTypeData::Integer(..))); + let parameters = variant.parameters.as_ref().unwrap(); + assert!(matches!(parameters[0].typ, UnresolvedTypeData::FieldElement)); + assert!(matches!(parameters[1].typ, UnresolvedTypeData::Integer(..))); let variant = noir_enum.variants.remove(0).item; assert_eq!("Z", variant.name.to_string()); - assert_eq!(variant.parameters.len(), 0); + assert!(variant.parameters.is_none()); } #[test] diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/expression.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/expression.rs index cbc68fbd7c1..eff309154e3 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/expression.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/expression.rs @@ -4,7 +4,7 @@ use noirc_errors::Span; use crate::{ ast::{ ArrayLiteral, BlockExpression, CallExpression, CastExpression, ConstructorExpression, - Expression, ExpressionKind, Ident, IfExpression, IndexExpression, Literal, + Expression, ExpressionKind, Ident, IfExpression, IndexExpression, Literal, MatchExpression, MemberAccessExpression, MethodCallExpression, Statement, TypePath, UnaryOp, UnresolvedType, }, parser::{labels::ParsingRuleLabel, parser::parse_many::separated_by_comma, ParserErrorReason}, @@ -91,8 +91,7 @@ impl<'a> Parser<'a> { } /// AtomOrUnaryRightExpression - /// = Atom - /// | UnaryRightExpression + /// = Atom UnaryRightExpression* fn parse_atom_or_unary_right(&mut self, allow_constructors: bool) -> Option { let start_span = self.current_token_span; let mut atom = self.parse_atom(allow_constructors)?; @@ -295,11 +294,13 @@ impl<'a> Parser<'a> { } // A constructor where the type is an interned unresolved type data is valid - if matches!(self.token.token(), Token::InternedUnresolvedTypeData(..)) - && self.next_is(Token::LeftBrace) + if matches!( + self.token.token(), + Token::InternedUnresolvedTypeData(..) | Token::QuotedType(..) + ) && self.next_is(Token::LeftBrace) { let span = self.current_token_span; - let typ = self.parse_interned_type().unwrap(); + let typ = self.parse_interned_type().or_else(|| self.parse_resolved_type()).unwrap(); self.eat_or_error(Token::LeftBrace); let typ = UnresolvedType { typ, span }; return Some(self.parse_constructor(typ)); @@ -309,6 +310,10 @@ impl<'a> Parser<'a> { return Some(kind); } + if let Some(kind) = self.parse_match_expr() { + return Some(kind); + } + if let Some(kind) = self.parse_lambda() { return Some(kind); } @@ -516,6 +521,49 @@ impl<'a> Parser<'a> { Some(ExpressionKind::If(Box::new(IfExpression { condition, consequence, alternative }))) } + /// MatchExpression = 'match' ExpressionExceptConstructor '{' MatchRule* '}' + pub(super) fn parse_match_expr(&mut self) -> Option { + let start_span = self.current_token_span; + if !self.eat_keyword(Keyword::Match) { + return None; + } + + let expression = self.parse_expression_except_constructor_or_error(); + + self.eat_left_brace(); + + let rules = self.parse_many( + "match cases", + without_separator().until(Token::RightBrace), + Self::parse_match_rule, + ); + + self.push_error(ParserErrorReason::ExperimentalFeature("Match expressions"), start_span); + Some(ExpressionKind::Match(Box::new(MatchExpression { expression, rules }))) + } + + /// MatchRule = Expression '->' (Block ','?) | (Expression ',') + fn parse_match_rule(&mut self) -> Option<(Expression, Expression)> { + let pattern = self.parse_expression()?; + self.eat_or_error(Token::FatArrow); + + let start_span = self.current_token_span; + let branch = match self.parse_block() { + Some(block) => { + let span = self.span_since(start_span); + let block = Expression::new(ExpressionKind::Block(block), span); + self.eat_comma(); // comma is optional if we have a block + block + } + None => { + let branch = self.parse_expression_or_error(); + self.eat_or_error(Token::Comma); + branch + } + }; + Some((pattern, branch)) + } + /// ComptimeExpression = 'comptime' Block fn parse_comptime_expr(&mut self) -> Option { if !self.eat_keyword(Keyword::Comptime) { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs index 005216b1deb..37013e91528 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/statement.rs @@ -162,10 +162,13 @@ impl<'a> Parser<'a> { } if let Some(kind) = self.parse_if_expr() { - return Some(StatementKind::Expression(Expression { - kind, - span: self.span_since(start_span), - })); + let span = self.span_since(start_span); + return Some(StatementKind::Expression(Expression { kind, span })); + } + + if let Some(kind) = self.parse_match_expr() { + let span = self.span_since(start_span); + return Some(StatementKind::Expression(Expression { kind, span })); } if let Some(block) = self.parse_block() { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs index 210bfe16bef..6b3575e19ee 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs @@ -316,7 +316,7 @@ impl<'a> Parser<'a> { Some(UnresolvedTypeData::AsTraitPath(Box::new(as_trait_path))) } - fn parse_resolved_type(&mut self) -> Option { + pub(super) fn parse_resolved_type(&mut self) -> Option { if let Some(token) = self.eat_kind(TokenKind::QuotedType) { match token.into_token() { Token::QuotedType(id) => { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 6acb3b4b59e..b7723ce4242 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -4178,3 +4178,19 @@ fn errors_on_loop_without_break_with_nested_loop() { CompilationError::ResolverError(ResolverError::LoopWithoutBreak { .. }) )); } + +#[test] +fn call_function_alias_type() { + let src = r#" + type Alias = fn[Env](Field) -> Field; + + fn main() { + call_fn(|x| x + 1); + } + + fn call_fn(f: Alias) { + assert_eq(f(0), 1); + } + "#; + assert_no_errors(src); +} diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index 1174a56dd33..c877c2f0529 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -91,6 +91,7 @@ "Elligator", "endianness", "envrc", + "EXPONENTIATE", "Flamegraph", "flate", "fmtstr", diff --git a/noir/noir-repo/docs/docs/how_to/how-to-oracles.md b/noir/noir-repo/docs/docs/how_to/how-to-oracles.md index 0bb8743e361..845c24c9829 100644 --- a/noir/noir-repo/docs/docs/how_to/how-to-oracles.md +++ b/noir/noir-repo/docs/docs/how_to/how-to-oracles.md @@ -14,7 +14,7 @@ sidebar_position: 1 This guide shows you how to use oracles in your Noir program. For the sake of clarity, it assumes that: - You have read the [explainer on Oracles](../explainers/explainer-oracle.md) and are comfortable with the concept. -- You have a Noir program to add oracles to. You can create one using the [vite-hardhat starter](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) as a boilerplate. +- You have a Noir program to add oracles to. You can create one using one of the starters in [awesome-noir](https://github.com/noir-lang/awesome-noir?tab=readme-ov-file#boilerplates). - You understand the concept of a JSON-RPC server. Visit the [JSON-RPC website](https://www.jsonrpc.org/) if you need a refresher. - You are comfortable with server-side JavaScript (e.g. Node.js, managing packages, etc.). diff --git a/noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.mdx b/noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.mdx index da36b60920d..09b659ee0f9 100644 --- a/noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.mdx +++ b/noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.mdx @@ -289,12 +289,10 @@ For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently suppo - Linea - Moonbeam -If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. +If you test any other chains, please open a PR on this page to update the list. ## What's next -Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). - -You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks. You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx b/noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx index 727ec6ca667..4442f94dc4c 100644 --- a/noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx +++ b/noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx @@ -60,29 +60,15 @@ Github comes with a default codespace and you can use it to code your own devcon #### 3. Create a folder called `.devcontainer` in the root of your repository. -#### 4. Create a Dockerfile in that folder, and paste the following code: - -```docker -FROM --platform=linux/amd64 node:lts-bookworm-slim -SHELL ["/bin/bash", "-c"] -RUN apt update && apt install -y curl bash git tar gzip libc++-dev -RUN curl -L https://raw.githubusercontent.com/noir-lang/noirup/main/install | bash -ENV PATH="/root/.nargo/bin:$PATH" -RUN noirup -ENTRYPOINT ["nargo"] -``` -#### 5. Create a file called `devcontainer.json` in the same folder, and paste the following code: +#### 4. Create a file called `devcontainer.json` in the same folder, and paste the following code: ```json { "name": "Noir on Codespaces", - "build": { - "context": ".", - "dockerfile": "Dockerfile" - }, - "customizations": { - "vscode": { - "extensions": ["noir-lang.vscode-noir"] + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/noir-lang/features/noir:latest": { + "version": "1.0.0-beta.1" } } } @@ -91,13 +77,8 @@ ENTRYPOINT ["nargo"] This will pull the new image and build it, so it could take a minute or so -#### 8. Done! -Just wait for the build to finish, and there's your easy Noir environment. - - -Refer to [noir-starter](https://github.com/noir-lang/noir-starter/) as an example of how devcontainers can be used together with codespaces. - - +#### 8. Done! +Just wait for the build to finish, and there's your easy Noir environment. Some examples of how to use it can be found in the [awesome-noir](https://github.com/noir-lang/awesome-noir?tab=readme-ov-file#boilerplates) repository. ## How do I use it? diff --git a/noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md index 29951ae843a..4b0a8001226 100644 --- a/noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md +++ b/noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md @@ -52,7 +52,7 @@ Structs can also be destructured in a pattern, binding each field to a new varia fn main() { let Animal { hands, legs: feet, eyes } = get_octopus(); - let ten = hands + feet + eyes as u8; + let ten = hands + feet + eyes as Field; } fn get_octopus() -> Animal { @@ -93,4 +93,4 @@ pub struct Animal { pub(crate) legs: Field, // accessible from the entire crate pub eyes: u8, // accessible from anywhere } -``` \ No newline at end of file +``` diff --git a/noir/noir-repo/docs/docs/tutorials/noirjs_app.md b/noir/noir-repo/docs/docs/tutorials/noirjs_app.md index cc61fff8405..d98cdf1ef56 100644 --- a/noir/noir-repo/docs/docs/tutorials/noirjs_app.md +++ b/noir/noir-repo/docs/docs/tutorials/noirjs_app.md @@ -301,6 +301,4 @@ If you want to continue learning by doing, here are some challenges for you: - Change the circuit to accept a [public input](../noir/concepts/data_types/#private--public-types) as the cutoff age. It could be different depending on the purpose, for example! - Enjoy Noir's Rust-like syntax and write a struct `Country` that implements a trait `MinAge` with a method `get_min_age`. Then, make a struct `Person` have an `u8` as its age and a country of type `Country`. You can pass a `person` in JS just like a JSON object `person: { age, country: { min_age: 18 }}` -The world is your stage, just have fun with ZK! You can see how noirjs is used in a full stack Next.js hardhat application in the [noir-starter repo here](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat). The example shows how to calculate a proof in the browser and verify it with a deployed Solidity verifier contract from noirjs. - -Check out other starters, tools, or just cool projects in the [awesome noir repository](https://github.com/noir-lang/awesome-noir). +The world is your stage, just have fun with ZK! You can see how noirjs is used in some common frameworks in the [awesome-noir repo](https://github.com/noir-lang/awesome-noir?tab=readme-ov-file#boilerplates). diff --git a/noir/noir-repo/docs/versioned_docs/version-v1.0.0-beta.1/how_to/how-to-solidity-verifier.mdx b/noir/noir-repo/docs/versioned_docs/version-v1.0.0-beta.1/how_to/how-to-solidity-verifier.mdx index da36b60920d..09b659ee0f9 100644 --- a/noir/noir-repo/docs/versioned_docs/version-v1.0.0-beta.1/how_to/how-to-solidity-verifier.mdx +++ b/noir/noir-repo/docs/versioned_docs/version-v1.0.0-beta.1/how_to/how-to-solidity-verifier.mdx @@ -289,12 +289,10 @@ For example, chains like `zkSync ERA` and `Polygon zkEVM` do not currently suppo - Linea - Moonbeam -If you test any other chains, please open a PR on this page to update the list. See [this doc](https://github.com/noir-lang/noir-starter/tree/main/with-foundry#testing-on-chain) for more info about testing verifier contracts on different EVM chains. +If you test any other chains, please open a PR on this page to update the list. ## What's next -Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks, such as [hardhat](https://github.com/noir-lang/noir-starter/tree/main/vite-hardhat) and [foundry](https://github.com/noir-lang/noir-starter/tree/main/with-foundry). - -You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. +Now that you know how to call a Noir Solidity Verifier on a smart contract using Remix, you should be comfortable with using it with some programmatic frameworks. You can find other tools, examples, boilerplates and libraries in the [awesome-noir](https://github.com/noir-lang/awesome-noir) repository. You should also be ready to write and deploy your first NoirJS app and start generating proofs on websites, phones, and NodeJS environments! Head on to the [NoirJS tutorial](../tutorials/noirjs_app.md) to learn how to do that. diff --git a/noir/noir-repo/noir_stdlib/src/array/check_shuffle.nr b/noir/noir-repo/noir_stdlib/src/array/check_shuffle.nr index 8fd2a34b49a..327f0559810 100644 --- a/noir/noir-repo/noir_stdlib/src/array/check_shuffle.nr +++ b/noir/noir-repo/noir_stdlib/src/array/check_shuffle.nr @@ -45,9 +45,6 @@ where /// Safety: shuffle_indices is ensured to be a permutation of 0..N, and then /// shuffle_indices is ensured to map lhs to rhs: assert(lhs[i] == rhs[shuffle_indices[i]]), for all i in 0..N unsafe { - /*@safety : shuffle_indices is ensured to be a permutation of 0..N, and then - shuffle_indices is ensured to map lhs to rhs: assert(lhs[i] == rhs[shuffle_indices[i]]), for all i in 0..N - */ let shuffle_indices = __get_shuffle_indices(lhs, rhs); for i in 0..N { diff --git a/noir/noir-repo/noir_stdlib/src/field/bn254.nr b/noir/noir-repo/noir_stdlib/src/field/bn254.nr index e589587ba81..a298a5d1e38 100644 --- a/noir/noir-repo/noir_stdlib/src/field/bn254.nr +++ b/noir/noir-repo/noir_stdlib/src/field/bn254.nr @@ -42,10 +42,6 @@ fn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) { /// if borrow is 0, it asserts that (alo > blo && ahi >= bhi) /// if borrow is 1, it asserts that (alo <= blo && ahi > bhi) unsafe { - /*@safety: borrow is enforced to be boolean due to its type. - if borrow is 0, it asserts that (alo > blo && ahi >= bhi) - if borrow is 1, it asserts that (alo <= blo && ahi > bhi) - */ let borrow = lte_hint(alo, blo); let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128; @@ -63,7 +59,6 @@ pub fn decompose(x: Field) -> (Field, Field) { } else { /// Safety: decomposition is properly checked below unsafe { - /*@safety: decomposition is properly checked below*/ // Take hints of the decomposition let (xlo, xhi) = decompose_hint(x); @@ -105,7 +100,6 @@ pub fn gt(a: Field, b: Field) -> bool { if is_unconstrained() { /// Safety: unsafe in unconstrained unsafe { - //@safety: unsafe in unconstrained field_less_than(b, a) } } else if a == b { @@ -113,7 +107,6 @@ pub fn gt(a: Field, b: Field) -> bool { } else { /// Safety: Take a hint of the comparison and verify it unsafe { - //@safety: Take a hint of the comparison and verify it if field_less_than(a, b) { assert_gt(b, a); false diff --git a/noir/noir-repo/noir_stdlib/src/field/mod.nr b/noir/noir-repo/noir_stdlib/src/field/mod.nr index d066ad2e9de..3dad654dfc7 100644 --- a/noir/noir-repo/noir_stdlib/src/field/mod.nr +++ b/noir/noir-repo/noir_stdlib/src/field/mod.nr @@ -317,7 +317,6 @@ fn lt_fallback(x: Field, y: Field) -> bool { if is_unconstrained() { /// Safety: unconstrained context unsafe { - //@safety : unconstrained context field_less_than(x, y) } } else { @@ -385,9 +384,15 @@ mod tests { #[test] // docs:start:to_be_radix_example fn test_to_be_radix() { - let field = 2; + // 259, in base 256, big endian, is [1, 3]. + // i.e. 3 * 256^0 + 1 * 256^1 + let field = 259; + + // The radix (in this example, 256) must be a power of 2. + // The length of the returned byte array can be specified to be + // >= the amount of space needed. let bytes: [u8; 8] = field.to_be_radix(256); - assert_eq(bytes, [0, 0, 0, 0, 0, 0, 0, 2]); + assert_eq(bytes, [0, 0, 0, 0, 0, 0, 1, 3]); assert_eq(Field::from_be_bytes::<8>(bytes), field); } // docs:end:to_be_radix_example @@ -395,9 +400,15 @@ mod tests { #[test] // docs:start:to_le_radix_example fn test_to_le_radix() { - let field = 2; + // 259, in base 256, little endian, is [3, 1]. + // i.e. 3 * 256^0 + 1 * 256^1 + let field = 259; + + // The radix (in this example, 256) must be a power of 2. + // The length of the returned byte array can be specified to be + // >= the amount of space needed. let bytes: [u8; 8] = field.to_le_radix(256); - assert_eq(bytes, [2, 0, 0, 0, 0, 0, 0, 0]); + assert_eq(bytes, [3, 1, 0, 0, 0, 0, 0, 0]); assert_eq(Field::from_le_bytes::<8>(bytes), field); } // docs:end:to_le_radix_example @@ -414,17 +425,17 @@ mod tests { } // TODO: Update this test to account for the Brillig restriction that the radix must be greater than 2 - // #[test] - // fn test_to_le_radix_brillig_1() { - // // this test should only fail in constrained mode - // if runtime::is_unconstrained() { - // let field = 1; - // let out: [u8; 8] = field.to_le_radix(1); - // crate::println(out); - // let expected = [0; 8]; - // assert(out == expected, "unexpected result"); - // } - // } + //#[test] + //fn test_to_le_radix_brillig_1() { + // // this test should only fail in constrained mode + // if runtime::is_unconstrained() { + // let field = 1; + // let out: [u8; 8] = field.to_le_radix(1); + // crate::println(out); + // let expected = [0; 8]; + // assert(out == expected, "unexpected result"); + // } + //} #[test(should_fail_with = "radix must be a power of 2")] fn test_to_le_radix_3() { @@ -461,17 +472,17 @@ mod tests { } // TODO: Update this test to account for the Brillig restriction that the radix must be less than 512 - // #[test] - // fn test_to_le_radix_brillig_512() { - // // this test should only fail in constrained mode - // if runtime::is_unconstrained() { - // let field = 1; - // let out: [u8; 8] = field.to_le_radix(512); - // let mut expected = [0; 8]; - // expected[0] = 1; - // assert(out == expected, "unexpected result"); - // } - // } + //#[test] + //fn test_to_le_radix_brillig_512() { + // // this test should only fail in constrained mode + // if runtime::is_unconstrained() { + // let field = 1; + // let out: [u8; 8] = field.to_le_radix(512); + // let mut expected = [0; 8]; + // expected[0] = 1; + // assert(out == expected, "unexpected result"); + // } + //} #[test] unconstrained fn test_field_less_than() { diff --git a/noir/noir-repo/noir_stdlib/src/lib.nr b/noir/noir-repo/noir_stdlib/src/lib.nr index 643027c5c3e..fb073516d29 100644 --- a/noir/noir-repo/noir_stdlib/src/lib.nr +++ b/noir/noir-repo/noir_stdlib/src/lib.nr @@ -42,7 +42,6 @@ unconstrained fn print_unconstrained(with_newline: bool, input: T) { pub fn println(input: T) { /// Safety: a print statement cannot be constrained unsafe { - //@safety: a print statement cannot be constrained print_unconstrained(true, input); } } @@ -50,7 +49,6 @@ pub fn println(input: T) { pub fn print(input: T) { /// Safety: a print statement cannot be constrained unsafe { - //@safety: a print statement cannot be constrained print_unconstrained(false, input); } } diff --git a/noir/noir-repo/noir_stdlib/src/uint128.nr b/noir/noir-repo/noir_stdlib/src/uint128.nr index 6c9b802f5b3..c053c0b339a 100644 --- a/noir/noir-repo/noir_stdlib/src/uint128.nr +++ b/noir/noir-repo/noir_stdlib/src/uint128.nr @@ -216,9 +216,6 @@ impl Div for U128 { /// Safety: euclidian division is asserted to be correct: assert(a == b * q + r); and assert(r < b); /// Furthermore, U128 addition and multiplication ensures that b * q + r does not overflow unsafe { - /*@safety : euclidian division is asserted to be correct: assert(a == b * q + r); and assert(r < b); - Furthermore, U128 addition and multiplication ensures that b * q + r does not overflow - */ let (q, r) = self.unconstrained_div(b); let a = b * q + r; assert_eq(self, a); @@ -232,7 +229,6 @@ impl Rem for U128 { fn rem(self: Self, b: U128) -> U128 { /// Safety: cf div() above unsafe { - //@safety : cf div() above let (q, r) = self.unconstrained_div(b); let a = b * q + r; assert_eq(self, a); @@ -461,7 +457,6 @@ mod tests { let d = U128::from_u64s_le(0x0, 0x1); /// Safety: testing context unsafe { - //@safety: testing context let (q, r) = a.unconstrained_div(b); assert_eq(q, c); assert_eq(r, d); @@ -472,7 +467,6 @@ mod tests { // Check the case where a is a multiple of b /// Safety: testing context unsafe { - //@safety: testing context let (c, d) = a.unconstrained_div(b); assert_eq((c, d), (a, U128::zero())); } @@ -480,7 +474,6 @@ mod tests { // Check where b is a multiple of a /// Safety: testing context unsafe { - //@safety: testing context let (c, d) = b.unconstrained_div(a); assert_eq((c, d), (U128::zero(), b)); } @@ -490,7 +483,6 @@ mod tests { let b = U128::zero(); /// Safety: testing context unsafe { - //@safety: testing context let (c, d) = a.unconstrained_div(b); assert_eq((c, d), (U128::zero(), U128::zero())); } @@ -499,7 +491,6 @@ mod tests { let b = U128::from_u64s_le(0x0, pow63 as u64); /// Safety: testing context unsafe { - //@safety: testing context let (c, d) = a.unconstrained_div(b); assert_eq((c, d), (U128::one(), U128::zero())); } diff --git a/noir/noir-repo/scripts/install_bb.sh b/noir/noir-repo/scripts/install_bb.sh index 3d1dc038ab8..72170af78d8 100755 --- a/noir/noir-repo/scripts/install_bb.sh +++ b/noir/noir-repo/scripts/install_bb.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.66.0" +VERSION="0.72.1" BBUP_PATH=~/.bb/bbup diff --git a/noir/noir-repo/test_programs/compilation_report.sh b/noir/noir-repo/test_programs/compilation_report.sh index 786dbd75fe8..66f1a53626e 100755 --- a/noir/noir-repo/test_programs/compilation_report.sh +++ b/noir/noir-repo/test_programs/compilation_report.sh @@ -6,7 +6,7 @@ current_dir=$(pwd) base_path="$current_dir/execution_success" # Tests to be profiled for compilation report -tests_to_profile=("sha256_regression" "regression_4709" "ram_blowup_regression") +tests_to_profile=("sha256_regression" "regression_4709" "ram_blowup_regression" "global_var_regression_entry_points") echo "{\"compilation_reports\": [ " > $current_dir/compilation_report.json diff --git a/noir/noir-repo/test_programs/compile_success_empty/acir_inside_brillig_recursion/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/acir_inside_brillig_recursion/src/main.nr index 608b205d852..12c663b2705 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/acir_inside_brillig_recursion/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/acir_inside_brillig_recursion/src/main.nr @@ -1,7 +1,6 @@ fn main() { /// Safety: testing context unsafe { - //@safety: testing context assert_eq(fibonacci(3), fibonacci_hint(3)); } } diff --git a/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr index 95571416e62..d7d0b1b8fa5 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr @@ -4,7 +4,6 @@ fn main() { /// Safety: testing context unsafe { - //@safety: testing context bool_casts(); field_casts(); uint_casts(); diff --git a/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr index 1b3366a8c6c..f55beb6d1a8 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr @@ -2,7 +2,6 @@ fn main() { /// Safety: testing context unsafe { - //@safety: testing context let x = 4; let y = 2; assert((x + y) == add(x, y)); diff --git a/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr index f1efd89378e..0e00f25e5bb 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr @@ -5,7 +5,6 @@ fn main() { /// Safety: testing context unsafe { - //@safety: testing context assert((x + y) == add(x, y)); assert((x - y) == sub(x, y)); diff --git a/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr index c2936400133..841d7d2dfca 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr @@ -4,7 +4,6 @@ fn main() { /// Safety: testing context unsafe { - //@safety: testing context assert(modulo(47, 3) == 2); assert(modulo(2, 3) == 2); assert(signed_modulo(5, 3) == 2); diff --git a/noir/noir-repo/test_programs/compile_success_empty/brillig_slice_input/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_slice_input/src/main.nr index 79612a98c05..c43c5fae162 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/brillig_slice_input/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/brillig_slice_input/src/main.nr @@ -18,7 +18,6 @@ fn main() { slice = slice.push_back([Point { x: 13, y: 14 }, Point { x: 20, y: 8 }]); /// Safety: testing context unsafe { - //@safety: testing context let brillig_sum = sum_slice(slice); assert_eq(brillig_sum, 55); } @@ -26,7 +25,6 @@ fn main() { slice = slice.push_back([Point { x: 15, y: 5 }, Point { x: 12, y: 13 }]); /// Safety: testing context unsafe { - //@safety: testing context let brillig_sum = sum_slice(slice); assert_eq(brillig_sum, 100); } diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/Nargo.toml new file mode 100644 index 00000000000..f72016f071a --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "comptime_enums" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/src/main.nr new file mode 100644 index 00000000000..e76792005ab --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/comptime_enums/src/main.nr @@ -0,0 +1,16 @@ +fn main() { + comptime { + let _two = Foo::Couple(1, 2); + let _one = Foo::One(3); + let _none = Foo::None; + + // Ensure zeroed works with enums + let _zeroed: Foo = std::mem::zeroed(); + } +} + +enum Foo { + Couple(i32, i32), + One(i32), + None, +} diff --git a/noir/noir-repo/test_programs/compile_success_empty/enums/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/enums/src/main.nr index 31619bca596..03a64d57dcf 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/enums/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/enums/src/main.nr @@ -3,9 +3,10 @@ fn main() { let _b: Foo = Foo::B(3); let _c = Foo::C(4); - // (#7172): Single variant enums must be called as functions currently let _d: fn() -> Foo<(i32, i32)> = Foo::D; let _d: Foo<(i32, i32)> = Foo::D(); + let _e: Foo = Foo::E; + let _e: Foo = Foo::E; // Ensure we can still use Foo::E polymorphically // Enum variants are functions and can be passed around as such let _many_cs = [1, 2, 3].map(Foo::C); @@ -15,5 +16,6 @@ enum Foo { A(Field, Field), B(u32), C(T), - D, + D(), + E, } diff --git a/noir/noir-repo/test_programs/compile_success_empty/is_unconstrained/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/is_unconstrained/src/main.nr index ea61c6caa76..856040b2274 100644 --- a/noir/noir-repo/test_programs/compile_success_empty/is_unconstrained/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_empty/is_unconstrained/src/main.nr @@ -11,7 +11,6 @@ unconstrained fn unconstrained_intermediate() { fn main() { /// Safety: testing context unsafe { - //@safety: testing context unconstrained_intermediate(); } check(false); diff --git a/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/Nargo.toml new file mode 100644 index 00000000000..2b26a729f87 --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "resolved_type_in_constructor" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/src/main.nr new file mode 100644 index 00000000000..5f1cbfd490f --- /dev/null +++ b/noir/noir-repo/test_programs/compile_success_empty/resolved_type_in_constructor/src/main.nr @@ -0,0 +1,10 @@ +fn main() { + let _ = my_macro!(); +} + +comptime fn my_macro() -> Quoted { + let typ = quote { Foo }.as_type(); + quote [$typ {}] +} + +struct Foo {} diff --git a/noir/noir-repo/test_programs/compile_success_with_bug/underconstrained_value_detector_5425/src/main.nr b/noir/noir-repo/test_programs/compile_success_with_bug/underconstrained_value_detector_5425/src/main.nr index cf1a8843503..22e2bc0b49d 100644 --- a/noir/noir-repo/test_programs/compile_success_with_bug/underconstrained_value_detector_5425/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_with_bug/underconstrained_value_detector_5425/src/main.nr @@ -11,7 +11,6 @@ unconstrained fn maximum_price(options: [u32; 3]) -> u32 { fn main(sandwiches: pub [u32; 3], drinks: pub [u32; 3], snacks: pub [u32; 3], best_value: u32) { /// Safety: testing context unsafe { - //@safety: testing context let meal_deal_cost: u32 = 390; let most_expensive_sandwich = maximum_price(sandwiches); let mut sandwich_exists = false; diff --git a/noir/noir-repo/test_programs/execution_failure/fold_nested_brillig_assert_fail/src/main.nr b/noir/noir-repo/test_programs/execution_failure/fold_nested_brillig_assert_fail/src/main.nr index 745efe27169..bbb6f8ff422 100644 --- a/noir/noir-repo/test_programs/execution_failure/fold_nested_brillig_assert_fail/src/main.nr +++ b/noir/noir-repo/test_programs/execution_failure/fold_nested_brillig_assert_fail/src/main.nr @@ -16,7 +16,6 @@ fn fold_conditional_wrapper(x: bool) -> Field { fn fold_conditional(x: bool) -> Field { /// Safety: testing context unsafe { - //@safety: testing context conditional_wrapper(x) } } diff --git a/noir/noir-repo/test_programs/execution_report.sh b/noir/noir-repo/test_programs/execution_report.sh index 827b7806d37..dcdc1bb8879 100755 --- a/noir/noir-repo/test_programs/execution_report.sh +++ b/noir/noir-repo/test_programs/execution_report.sh @@ -6,7 +6,7 @@ current_dir=$(pwd) base_path="$current_dir/execution_success" # Tests to be profiled for execution report -tests_to_profile=("sha256_regression" "regression_4709" "ram_blowup_regression") +tests_to_profile=("sha256_regression" "regression_4709" "ram_blowup_regression" "global_var_regression_entry_points") echo "{\"execution_reports\": [ " > $current_dir/execution_report.json diff --git a/noir/noir-repo/test_programs/execution_success/array_to_slice_constant_length/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_to_slice_constant_length/src/main.nr index 0d307289dea..1d29db4973a 100644 --- a/noir/noir-repo/test_programs/execution_success/array_to_slice_constant_length/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/array_to_slice_constant_length/src/main.nr @@ -6,7 +6,6 @@ unconstrained fn return_array(val: Field) -> [Field; 1] { fn main(val: Field) { /// Safety: testing context unsafe { - //@safety: testing context let array = return_array(val); assert_constant(array.as_slice().len()); } diff --git a/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr b/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr index 7f423d27c01..2095c92349a 100644 --- a/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr @@ -19,7 +19,6 @@ fn main(mut x: [u8; 5], y: [u8; 5]) { } else { /// Safety: testing context unsafe { - //@safety: testing context test_unconstrained2(a, b) } }; diff --git a/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr index 7b6604ab221..a327dfd7533 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr @@ -1,7 +1,6 @@ fn main(x: u32) { /// Safety: testing context unsafe { - //@safety: testing context assert(entry_point(x) == 2); swap_entry_point(x, x + 1); assert(deep_entry_point(x) == 4); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr index 75ba1eeda18..f0524842ac6 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr @@ -4,7 +4,6 @@ fn main(x: [Field; 3]) { /// Safety: testing context unsafe { - //@safety: testing context read_array(x); read_write_array(x); } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr index b5c89bbbfb5..7e567b84139 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr @@ -4,7 +4,6 @@ fn main(x: [u8; 5], result: [u8; 32]) { /// Safety: testing context unsafe { - //@safety: testing context assert(blake2s(x) == result); } } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr index 5bd3458da51..c76d7651b0a 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr @@ -3,7 +3,6 @@ // The features being tested is brillig calls fn main(x: u32) { unsafe { - /*@safety : testing context*/ assert(entry_point(x) == 2); swap_entry_point(x, x + 1); assert(deep_entry_point(x) == 4); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr index d2594f26070..b27eb30da17 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr @@ -4,7 +4,6 @@ fn main(x: [u32; 3]) { /// Safety: testing context unsafe { - //@safety: testing context assert(entry_point(x) == 9); another_entry_point(x); } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr index 4f40d8c2404..31b70cb12cf 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr @@ -4,7 +4,6 @@ fn main(x: [u32; 3]) { /// Safety: testing context unsafe { - //@safety: testing context assert(entry_point(x[0]) == 7); assert(entry_point(x[1]) == 8); assert(entry_point(x[2]) == 9); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr index f90ffa5ae4b..024ee52d5af 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr @@ -4,7 +4,6 @@ fn main(x: Field) { /// Safety: testing context unsafe { - //@safety: testing context assert(4 == conditional(x == 1)); } } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr index b6264606ea7..ff1c36c9ddf 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr @@ -5,7 +5,6 @@ struct MyStruct { fn main(x: u32) { /// Safety: testing context unsafe { - //@safety: testing context assert(wrapper(increment, x) == x + 1); assert(wrapper(increment_acir, x) == x + 1); assert(wrapper(decrement, x) == x - 1); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr index df6092255da..b676c46120e 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr @@ -8,7 +8,6 @@ struct myStruct { fn main(x: Field) { /// Safety: testing context unsafe { - //@safety: testing context assert(x == identity(x)); // TODO: add support for array comparison let arr = identity_array([x, x]); diff --git a/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr index f750c75dcef..feb5433738f 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr @@ -30,7 +30,6 @@ unconstrained fn create_and_assert_inside_brillig(x: Field, y: Field) { fn main(x: Field, y: Field) { /// Safety: testing context unsafe { - //@safety: testing context let header = Header { params: [1, 2, 3] }; let note0 = MyNote { array: [1, 2], plain: 3, header }; let note1 = MyNote { array: [4, 5], plain: 6, header }; diff --git a/noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr index f4bbc4d1057..6dc91f86127 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr @@ -4,7 +4,6 @@ fn main(x: Field, y: Field) { /// Safety: testing context unsafe { - //@safety: testing context assert(false == not_operator(x as bool)); assert(true == not_operator(y as bool)); } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr index 2d4ecaf7f93..e7140ffa06c 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr @@ -4,7 +4,6 @@ fn main(x: u32) { /// Safety: testing context unsafe { - //@safety: testing context assert(fibonacci(x) == 55); } } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_uninitialized_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_uninitialized_arrays/src/main.nr index 51dd758cd9c..39a13440ca9 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_uninitialized_arrays/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_uninitialized_arrays/src/main.nr @@ -1,7 +1,6 @@ fn main(x: Field, y: Field) -> pub Field { /// Safety: testing context unsafe { - //@safety: testing context let notes = create_notes(x, y); sum_x(notes, x, y) } diff --git a/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Nargo.toml b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Nargo.toml new file mode 100644 index 00000000000..34fe5d788a2 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "dont_deduplicate_call" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Prover.toml b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Prover.toml new file mode 100644 index 00000000000..d66a8c53d09 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/Prover.toml @@ -0,0 +1,2 @@ +x = 0 +active = false diff --git a/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/src/main.nr b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/src/main.nr new file mode 100644 index 00000000000..cb658eab763 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/dont_deduplicate_call/src/main.nr @@ -0,0 +1,16 @@ +fn main(x: Field, active: bool) { + let mut x1 = false; + /// Safety:) + unsafe { + if active { + x1 = foo(x); + } + + let x2 = foo(x); + assert(x2); + } +} + +unconstrained fn foo(_x: Field) -> bool { + true +} diff --git a/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Nargo.toml b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Nargo.toml new file mode 100644 index 00000000000..bdcfc46a0f6 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "global_var_regression_entry_points" +type = "bin" +authors = [""] + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Prover.toml b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Prover.toml new file mode 100644 index 00000000000..4c144083f00 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/Prover.toml @@ -0,0 +1,2 @@ +x = 0 +y = 1 diff --git a/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/consts.nr b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/consts.nr new file mode 100644 index 00000000000..7ad6a4a54d1 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/consts.nr @@ -0,0 +1,3842 @@ +global EXPONENTIATE: [[Field; 257]; 257] = [ + [ + 1, 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, 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, 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, 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, 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, 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, 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, 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, + ], + [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, + ], + [ + 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, + 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, + 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, + 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, + 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, + 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, + 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, + 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, + 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, + 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, + 8, 16, 32, 64, 128, 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, + 256, 255, 253, 249, 241, 225, 193, 129, 1, 2, 4, 8, 16, 32, 64, 128, 256, 255, 253, 249, + 241, 225, 193, 129, 1, + ], + [ + 1, 3, 9, 27, 81, 243, 215, 131, 136, 151, 196, 74, 222, 152, 199, 83, 249, 233, 185, 41, + 123, 112, 79, 237, 197, 77, 231, 179, 23, 69, 207, 107, 64, 192, 62, 186, 44, 132, 139, 160, + 223, 155, 208, 110, 73, 219, 143, 172, 2, 6, 18, 54, 162, 229, 173, 5, 15, 45, 135, 148, + 187, 47, 141, 166, 241, 209, 113, 82, 246, 224, 158, 217, 137, 154, 205, 101, 46, 138, 157, + 214, 128, 127, 124, 115, 88, 7, 21, 63, 189, 53, 159, 220, 146, 181, 29, 87, 4, 12, 36, 108, + 67, 201, 89, 10, 30, 90, 13, 39, 117, 94, 25, 75, 225, 161, 226, 164, 235, 191, 59, 177, 17, + 51, 153, 202, 92, 19, 57, 171, 256, 254, 248, 230, 176, 14, 42, 126, 121, 106, 61, 183, 35, + 105, 58, 174, 8, 24, 72, 216, 134, 145, 178, 20, 60, 180, 26, 78, 234, 188, 50, 150, 193, + 65, 195, 71, 213, 125, 118, 97, 34, 102, 49, 147, 184, 38, 114, 85, 255, 251, 239, 203, 95, + 28, 84, 252, 242, 212, 122, 109, 70, 210, 116, 91, 16, 48, 144, 175, 11, 33, 99, 40, 120, + 103, 52, 156, 211, 119, 100, 43, 129, 130, 133, 142, 169, 250, 236, 194, 68, 204, 98, 37, + 111, 76, 228, 170, 253, 245, 221, 149, 190, 56, 168, 247, 227, 167, 244, 218, 140, 163, 232, + 182, 32, 96, 31, 93, 22, 66, 198, 80, 240, 206, 104, 55, 165, 238, 200, 86, 1, + ], + [ + 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, + 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, + 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, + 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, + 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, + 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, + 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, + 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, + 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, + 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, + 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, + 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, 4, 16, 64, 256, 253, 241, 193, 1, + ], + [ + 1, 5, 25, 125, 111, 41, 205, 254, 242, 182, 139, 181, 134, 156, 9, 45, 225, 97, 228, 112, + 46, 230, 122, 96, 223, 87, 178, 119, 81, 148, 226, 102, 253, 237, 157, 14, 70, 93, 208, 12, + 60, 43, 215, 47, 235, 147, 221, 77, 128, 126, 116, 66, 73, 108, 26, 130, 136, 166, 59, 38, + 190, 179, 124, 106, 16, 80, 143, 201, 234, 142, 196, 209, 17, 85, 168, 69, 88, 183, 144, + 206, 2, 10, 50, 250, 222, 82, 153, 251, 227, 107, 21, 105, 11, 55, 18, 90, 193, 194, 199, + 224, 92, 203, 244, 192, 189, 174, 99, 238, 162, 39, 195, 204, 249, 217, 57, 28, 140, 186, + 159, 24, 120, 86, 173, 94, 213, 37, 185, 154, 256, 252, 232, 132, 146, 216, 52, 3, 15, 75, + 118, 76, 123, 101, 248, 212, 32, 160, 29, 145, 211, 27, 135, 161, 34, 170, 79, 138, 176, + 109, 31, 155, 4, 20, 100, 243, 187, 164, 49, 245, 197, 214, 42, 210, 22, 110, 36, 180, 129, + 131, 141, 191, 184, 149, 231, 127, 121, 91, 198, 219, 67, 78, 133, 151, 241, 177, 114, 56, + 23, 115, 61, 48, 240, 172, 89, 188, 169, 74, 113, 51, 255, 247, 207, 7, 35, 175, 104, 6, 30, + 150, 236, 152, 246, 202, 239, 167, 64, 63, 58, 33, 165, 54, 13, 65, 68, 83, 158, 19, 95, + 218, 62, 53, 8, 40, 200, 229, 117, 71, 98, 233, 137, 171, 84, 163, 44, 220, 72, 103, 1, + ], + [ + 1, 6, 36, 216, 11, 66, 139, 63, 121, 212, 244, 179, 46, 19, 114, 170, 249, 209, 226, 71, + 169, 243, 173, 10, 60, 103, 104, 110, 146, 105, 116, 182, 64, 127, 248, 203, 190, 112, 158, + 177, 34, 204, 196, 148, 117, 188, 100, 86, 2, 12, 72, 175, 22, 132, 21, 126, 242, 167, 231, + 101, 92, 38, 228, 83, 241, 161, 195, 142, 81, 229, 89, 20, 120, 206, 208, 220, 35, 210, 232, + 107, 128, 254, 239, 149, 123, 224, 59, 97, 68, 151, 135, 39, 234, 119, 200, 172, 4, 24, 144, + 93, 44, 7, 42, 252, 227, 77, 205, 202, 184, 76, 199, 166, 225, 65, 133, 27, 162, 201, 178, + 40, 240, 155, 159, 183, 70, 163, 207, 214, 256, 251, 221, 41, 246, 191, 118, 194, 136, 45, + 13, 78, 211, 238, 143, 87, 8, 48, 31, 186, 88, 14, 84, 247, 197, 154, 153, 147, 111, 152, + 141, 75, 193, 130, 9, 54, 67, 145, 99, 80, 223, 53, 61, 109, 140, 69, 157, 171, 255, 245, + 185, 82, 235, 125, 236, 131, 15, 90, 26, 156, 165, 219, 29, 174, 16, 96, 62, 115, 176, 28, + 168, 237, 137, 51, 49, 37, 222, 47, 25, 150, 129, 3, 18, 108, 134, 33, 198, 160, 189, 106, + 122, 218, 23, 138, 57, 85, 253, 233, 113, 164, 213, 250, 215, 5, 30, 180, 52, 55, 73, 181, + 58, 91, 32, 192, 124, 230, 95, 56, 79, 217, 17, 102, 98, 74, 187, 94, 50, 43, 1, + ], + [ + 1, 7, 49, 86, 88, 102, 200, 115, 34, 238, 124, 97, 165, 127, 118, 55, 128, 125, 104, 214, + 213, 206, 157, 71, 240, 138, 195, 80, 46, 65, 198, 101, 193, 66, 205, 150, 22, 154, 50, 93, + 137, 188, 31, 217, 234, 96, 158, 78, 32, 224, 26, 182, 246, 180, 232, 82, 60, 163, 113, 20, + 140, 209, 178, 218, 241, 145, 244, 166, 134, 167, 141, 216, 227, 47, 72, 247, 187, 24, 168, + 148, 8, 56, 135, 174, 190, 45, 58, 149, 15, 105, 221, 5, 35, 245, 173, 183, 253, 229, 61, + 170, 162, 106, 228, 54, 121, 76, 18, 126, 111, 6, 42, 37, 2, 14, 98, 172, 176, 204, 143, + 230, 68, 219, 248, 194, 73, 254, 236, 110, 256, 250, 208, 171, 169, 155, 57, 142, 223, 19, + 133, 160, 92, 130, 139, 202, 129, 132, 153, 43, 44, 51, 100, 186, 17, 119, 62, 177, 211, + 192, 59, 156, 64, 191, 52, 107, 235, 103, 207, 164, 120, 69, 226, 40, 23, 161, 99, 179, 225, + 33, 231, 75, 11, 77, 25, 175, 197, 94, 144, 237, 117, 48, 79, 39, 16, 112, 13, 91, 123, 90, + 116, 41, 30, 210, 185, 10, 70, 233, 89, 109, 249, 201, 122, 83, 67, 212, 199, 108, 242, 152, + 36, 252, 222, 12, 84, 74, 4, 28, 196, 87, 95, 151, 29, 203, 136, 181, 239, 131, 146, 251, + 215, 220, 255, 243, 159, 85, 81, 53, 114, 27, 189, 38, 9, 63, 184, 3, 21, 147, 1, + ], + [ + 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, + 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, + 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, + 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, + 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, + 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, + 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, + 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, + 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, + 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, + 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, + 32, 256, 249, 193, 2, 16, 128, 253, 225, 1, 8, 64, 255, 241, 129, 4, 32, 256, 249, 193, 2, + 16, 128, 253, 225, 1, + ], + [ + 1, 9, 81, 215, 136, 196, 222, 199, 249, 185, 123, 79, 197, 231, 23, 207, 64, 62, 44, 139, + 223, 208, 73, 143, 2, 18, 162, 173, 15, 135, 187, 141, 241, 113, 246, 158, 137, 205, 46, + 157, 128, 124, 88, 21, 189, 159, 146, 29, 4, 36, 67, 89, 30, 13, 117, 25, 225, 226, 235, 59, + 17, 153, 92, 57, 256, 248, 176, 42, 121, 61, 35, 58, 8, 72, 134, 178, 60, 26, 234, 50, 193, + 195, 213, 118, 34, 49, 184, 114, 255, 239, 95, 84, 242, 122, 70, 116, 16, 144, 11, 99, 120, + 52, 211, 100, 129, 133, 169, 236, 68, 98, 111, 228, 253, 221, 190, 168, 227, 244, 140, 232, + 32, 31, 22, 198, 240, 104, 165, 200, 1, 9, 81, 215, 136, 196, 222, 199, 249, 185, 123, 79, + 197, 231, 23, 207, 64, 62, 44, 139, 223, 208, 73, 143, 2, 18, 162, 173, 15, 135, 187, 141, + 241, 113, 246, 158, 137, 205, 46, 157, 128, 124, 88, 21, 189, 159, 146, 29, 4, 36, 67, 89, + 30, 13, 117, 25, 225, 226, 235, 59, 17, 153, 92, 57, 256, 248, 176, 42, 121, 61, 35, 58, 8, + 72, 134, 178, 60, 26, 234, 50, 193, 195, 213, 118, 34, 49, 184, 114, 255, 239, 95, 84, 242, + 122, 70, 116, 16, 144, 11, 99, 120, 52, 211, 100, 129, 133, 169, 236, 68, 98, 111, 228, 253, + 221, 190, 168, 227, 244, 140, 232, 32, 31, 22, 198, 240, 104, 165, 200, 1, + ], + [ + 1, 10, 100, 229, 234, 27, 13, 130, 15, 150, 215, 94, 169, 148, 195, 151, 225, 194, 141, 125, + 222, 164, 98, 209, 34, 83, 59, 76, 246, 147, 185, 51, 253, 217, 114, 112, 92, 149, 205, 251, + 197, 171, 168, 138, 95, 179, 248, 167, 128, 252, 207, 14, 140, 115, 122, 192, 121, 182, 21, + 210, 44, 183, 31, 53, 16, 160, 58, 66, 146, 175, 208, 24, 240, 87, 99, 219, 134, 55, 36, + 103, 2, 20, 200, 201, 211, 54, 26, 3, 30, 43, 173, 188, 81, 39, 133, 45, 193, 131, 25, 250, + 187, 71, 196, 161, 68, 166, 118, 152, 235, 37, 113, 102, 249, 177, 228, 224, 184, 41, 153, + 245, 137, 85, 79, 19, 190, 101, 239, 77, 256, 247, 157, 28, 23, 230, 244, 127, 242, 107, 42, + 163, 88, 109, 62, 106, 32, 63, 116, 132, 35, 93, 159, 48, 223, 174, 198, 181, 11, 110, 72, + 206, 4, 40, 143, 145, 165, 108, 52, 6, 60, 86, 89, 119, 162, 78, 9, 90, 129, 5, 50, 243, + 117, 142, 135, 65, 136, 75, 236, 47, 213, 74, 226, 204, 241, 97, 199, 191, 111, 82, 49, 233, + 17, 170, 158, 38, 123, 202, 221, 154, 255, 237, 57, 56, 46, 203, 231, 254, 227, 214, 84, 69, + 176, 218, 124, 212, 64, 126, 232, 7, 70, 186, 61, 96, 189, 91, 139, 105, 22, 220, 144, 155, + 8, 80, 29, 33, 73, 216, 104, 12, 120, 172, 178, 238, 67, 156, 18, 180, 1, + ], + [ + 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, + 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, + 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, + 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, 242, 92, 241, 81, + 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, 136, 211, 8, 88, + 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, 134, 189, 23, 253, + 213, 30, 73, 32, 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, 34, 117, 2, 22, + 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, 240, 70, 256, 246, + 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, 137, 222, 129, + 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1, 11, 121, 46, 249, 169, 60, 146, 64, 190, + 34, 117, 2, 22, 242, 92, 241, 81, 120, 35, 128, 123, 68, 234, 4, 44, 227, 184, 225, 162, + 240, 70, 256, 246, 136, 211, 8, 88, 197, 111, 193, 67, 223, 140, 255, 235, 15, 165, 16, 176, + 137, 222, 129, 134, 189, 23, 253, 213, 30, 73, 32, 95, 17, 187, 1, + ], + [ + 1, 12, 144, 186, 176, 56, 158, 97, 136, 90, 52, 110, 35, 163, 157, 85, 249, 161, 133, 54, + 134, 66, 21, 252, 197, 51, 98, 148, 234, 238, 29, 91, 64, 254, 221, 82, 213, 243, 89, 40, + 223, 106, 244, 101, 184, 152, 25, 43, 2, 24, 31, 115, 95, 112, 59, 194, 15, 180, 104, 220, + 70, 69, 57, 170, 241, 65, 9, 108, 11, 132, 42, 247, 137, 102, 196, 39, 211, 219, 58, 182, + 128, 251, 185, 164, 169, 229, 178, 80, 189, 212, 231, 202, 111, 47, 50, 86, 4, 48, 62, 230, + 190, 224, 118, 131, 30, 103, 208, 183, 140, 138, 114, 83, 225, 130, 18, 216, 22, 7, 84, 237, + 17, 204, 135, 78, 165, 181, 116, 107, 256, 245, 113, 71, 81, 201, 99, 160, 121, 167, 205, + 147, 222, 94, 100, 172, 8, 96, 124, 203, 123, 191, 236, 5, 60, 206, 159, 109, 23, 19, 228, + 166, 193, 3, 36, 175, 44, 14, 168, 217, 34, 151, 13, 156, 73, 105, 232, 214, 255, 233, 226, + 142, 162, 145, 198, 63, 242, 77, 153, 37, 187, 188, 200, 87, 16, 192, 248, 149, 246, 125, + 215, 10, 120, 155, 61, 218, 46, 38, 199, 75, 129, 6, 72, 93, 88, 28, 79, 177, 68, 45, 26, + 55, 146, 210, 207, 171, 253, 209, 195, 27, 67, 33, 139, 126, 227, 154, 49, 74, 117, 119, + 143, 174, 32, 127, 239, 41, 235, 250, 173, 20, 240, 53, 122, 179, 92, 76, 141, 150, 1, + ], + [ + 1, 13, 169, 141, 34, 185, 92, 168, 128, 122, 44, 58, 240, 36, 211, 173, 193, 196, 235, 228, + 137, 239, 23, 42, 32, 159, 11, 143, 60, 9, 117, 236, 241, 49, 123, 57, 227, 124, 70, 139, 8, + 104, 67, 100, 15, 195, 222, 59, 253, 205, 95, 207, 121, 31, 146, 99, 2, 26, 81, 25, 68, 113, + 184, 79, 256, 244, 88, 116, 223, 72, 165, 89, 129, 135, 213, 199, 17, 221, 46, 84, 64, 61, + 22, 29, 120, 18, 234, 215, 225, 98, 246, 114, 197, 248, 140, 21, 16, 208, 134, 200, 30, 133, + 187, 118, 249, 153, 190, 157, 242, 62, 35, 198, 4, 52, 162, 50, 136, 226, 111, 158, 255, + 231, 176, 232, 189, 144, 73, 178, 1, 13, 169, 141, 34, 185, 92, 168, 128, 122, 44, 58, 240, + 36, 211, 173, 193, 196, 235, 228, 137, 239, 23, 42, 32, 159, 11, 143, 60, 9, 117, 236, 241, + 49, 123, 57, 227, 124, 70, 139, 8, 104, 67, 100, 15, 195, 222, 59, 253, 205, 95, 207, 121, + 31, 146, 99, 2, 26, 81, 25, 68, 113, 184, 79, 256, 244, 88, 116, 223, 72, 165, 89, 129, 135, + 213, 199, 17, 221, 46, 84, 64, 61, 22, 29, 120, 18, 234, 215, 225, 98, 246, 114, 197, 248, + 140, 21, 16, 208, 134, 200, 30, 133, 187, 118, 249, 153, 190, 157, 242, 62, 35, 198, 4, 52, + 162, 50, 136, 226, 111, 158, 255, 231, 176, 232, 189, 144, 73, 178, 1, + ], + [ + 1, 14, 196, 174, 123, 180, 207, 71, 223, 38, 18, 252, 187, 48, 158, 156, 128, 250, 159, 170, + 67, 167, 25, 93, 17, 238, 248, 131, 35, 233, 178, 179, 193, 132, 49, 172, 95, 45, 116, 82, + 120, 138, 133, 63, 111, 12, 168, 39, 32, 191, 104, 171, 81, 106, 199, 216, 197, 188, 62, 97, + 73, 251, 173, 109, 241, 33, 205, 43, 88, 204, 29, 149, 30, 163, 226, 80, 92, 3, 42, 74, 8, + 112, 26, 107, 213, 155, 114, 54, 242, 47, 144, 217, 211, 127, 236, 220, 253, 201, 244, 75, + 22, 51, 200, 230, 136, 105, 185, 20, 23, 65, 139, 147, 2, 28, 135, 91, 246, 103, 157, 142, + 189, 76, 36, 247, 117, 96, 59, 55, 256, 243, 61, 83, 134, 77, 50, 186, 34, 219, 239, 5, 70, + 209, 99, 101, 129, 7, 98, 87, 190, 90, 232, 164, 240, 19, 9, 126, 222, 24, 79, 78, 64, 125, + 208, 85, 162, 212, 141, 175, 137, 119, 124, 194, 146, 245, 89, 218, 225, 66, 153, 86, 176, + 151, 58, 41, 60, 69, 195, 160, 184, 6, 84, 148, 16, 224, 52, 214, 169, 53, 228, 108, 227, + 94, 31, 177, 165, 254, 215, 183, 249, 145, 231, 150, 44, 102, 143, 203, 15, 210, 113, 40, + 46, 130, 21, 37, 4, 56, 13, 182, 235, 206, 57, 27, 121, 152, 72, 237, 234, 192, 118, 110, + 255, 229, 122, 166, 11, 154, 100, 115, 68, 181, 221, 10, 140, 161, 198, 202, 1, + ], + [ + 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, + 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, + 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, + 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, + 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, + 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, + 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, + 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, + 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, + 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, + 68, 249, 137, 256, 242, 32, 223, 4, 60, 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, 15, + 225, 34, 253, 197, 128, 121, 16, 240, 2, 30, 193, 68, 249, 137, 256, 242, 32, 223, 4, 60, + 129, 136, 241, 17, 255, 227, 64, 189, 8, 120, 1, + ], + [ + 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, + 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, + 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, + 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, + 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, + 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, + 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, + 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, + 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, + 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, + 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, + 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, 16, 256, 241, 1, + ], + [ + 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, + 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, + 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, + 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, + 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, + 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, + 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, + 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, + 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, + 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, + 197, 8, 136, 256, 240, 225, 227, 4, 68, 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, 17, + 32, 30, 253, 189, 129, 137, 16, 15, 255, 223, 193, 197, 8, 136, 256, 240, 225, 227, 4, 68, + 128, 120, 241, 242, 2, 34, 64, 60, 249, 121, 1, + ], + [ + 1, 18, 67, 178, 120, 104, 73, 29, 8, 144, 22, 139, 189, 61, 70, 232, 64, 124, 176, 84, 227, + 231, 46, 57, 255, 221, 123, 158, 17, 49, 111, 199, 241, 226, 213, 236, 136, 135, 117, 50, + 129, 9, 162, 89, 60, 52, 165, 143, 4, 72, 11, 198, 223, 159, 35, 116, 32, 62, 88, 42, 242, + 244, 23, 157, 256, 239, 190, 79, 137, 153, 184, 228, 249, 113, 235, 118, 68, 196, 187, 25, + 193, 133, 81, 173, 30, 26, 211, 200, 2, 36, 134, 99, 240, 208, 146, 58, 16, 31, 44, 21, 121, + 122, 140, 207, 128, 248, 95, 168, 197, 205, 92, 114, 253, 185, 246, 59, 34, 98, 222, 141, + 225, 195, 169, 215, 15, 13, 234, 100, 1, 18, 67, 178, 120, 104, 73, 29, 8, 144, 22, 139, + 189, 61, 70, 232, 64, 124, 176, 84, 227, 231, 46, 57, 255, 221, 123, 158, 17, 49, 111, 199, + 241, 226, 213, 236, 136, 135, 117, 50, 129, 9, 162, 89, 60, 52, 165, 143, 4, 72, 11, 198, + 223, 159, 35, 116, 32, 62, 88, 42, 242, 244, 23, 157, 256, 239, 190, 79, 137, 153, 184, 228, + 249, 113, 235, 118, 68, 196, 187, 25, 193, 133, 81, 173, 30, 26, 211, 200, 2, 36, 134, 99, + 240, 208, 146, 58, 16, 31, 44, 21, 121, 122, 140, 207, 128, 248, 95, 168, 197, 205, 92, 114, + 253, 185, 246, 59, 34, 98, 222, 141, 225, 195, 169, 215, 15, 13, 234, 100, 1, + ], + [ + 1, 19, 104, 177, 22, 161, 232, 39, 227, 201, 221, 87, 111, 53, 236, 115, 129, 138, 52, 217, + 11, 209, 116, 148, 242, 229, 239, 172, 184, 155, 118, 186, 193, 69, 26, 237, 134, 233, 58, + 74, 121, 243, 248, 86, 92, 206, 59, 93, 225, 163, 13, 247, 67, 245, 29, 37, 189, 250, 124, + 43, 46, 103, 158, 175, 241, 210, 135, 252, 162, 251, 143, 147, 223, 125, 62, 150, 23, 180, + 79, 216, 249, 105, 196, 126, 81, 254, 200, 202, 240, 191, 31, 75, 140, 90, 168, 108, 253, + 181, 98, 63, 169, 127, 100, 101, 120, 224, 144, 166, 70, 45, 84, 54, 255, 219, 49, 160, 213, + 192, 50, 179, 60, 112, 72, 83, 35, 151, 42, 27, 256, 238, 153, 80, 235, 96, 25, 218, 30, 56, + 36, 170, 146, 204, 21, 142, 128, 119, 205, 40, 246, 48, 141, 109, 15, 28, 18, 85, 73, 102, + 139, 71, 64, 188, 231, 20, 123, 24, 199, 183, 136, 14, 9, 171, 165, 51, 198, 164, 32, 94, + 244, 10, 190, 12, 228, 220, 68, 7, 133, 214, 211, 154, 99, 82, 16, 47, 122, 5, 95, 6, 114, + 110, 34, 132, 195, 107, 234, 77, 178, 41, 8, 152, 61, 131, 176, 3, 57, 55, 17, 66, 226, 182, + 117, 167, 89, 149, 4, 76, 159, 194, 88, 130, 157, 156, 137, 33, 113, 91, 187, 212, 173, 203, + 2, 38, 208, 97, 44, 65, 207, 78, 197, 145, 185, 174, 222, 106, 215, 230, 1, + ], + [ + 1, 20, 143, 33, 146, 93, 61, 192, 242, 214, 168, 19, 123, 147, 113, 204, 225, 131, 50, 229, + 211, 108, 104, 24, 223, 91, 21, 163, 176, 179, 239, 154, 253, 177, 199, 125, 187, 142, 13, + 3, 60, 172, 99, 181, 22, 183, 62, 212, 128, 247, 57, 112, 184, 82, 98, 161, 136, 150, 173, + 119, 67, 55, 72, 155, 16, 63, 232, 14, 23, 203, 205, 245, 17, 83, 118, 47, 169, 39, 9, 180, + 2, 40, 29, 66, 35, 186, 122, 127, 227, 171, 79, 38, 246, 37, 226, 151, 193, 5, 100, 201, + 165, 216, 208, 48, 189, 182, 42, 69, 95, 101, 221, 51, 249, 97, 141, 250, 117, 27, 26, 6, + 120, 87, 198, 105, 44, 109, 124, 167, 256, 237, 114, 224, 111, 164, 196, 65, 15, 43, 89, + 238, 134, 110, 144, 53, 32, 126, 207, 28, 46, 149, 153, 233, 34, 166, 236, 94, 81, 78, 18, + 103, 4, 80, 58, 132, 70, 115, 244, 254, 197, 85, 158, 76, 235, 74, 195, 45, 129, 10, 200, + 145, 73, 175, 159, 96, 121, 107, 84, 138, 190, 202, 185, 102, 241, 194, 25, 243, 234, 54, + 52, 12, 240, 174, 139, 210, 88, 218, 248, 77, 255, 217, 228, 191, 222, 71, 135, 130, 30, 86, + 178, 219, 11, 220, 31, 106, 64, 252, 157, 56, 92, 41, 49, 209, 68, 75, 215, 188, 162, 156, + 36, 206, 8, 160, 116, 7, 140, 230, 231, 251, 137, 170, 59, 152, 213, 148, 133, 90, 1, + ], + [ + 1, 21, 184, 9, 189, 114, 81, 159, 255, 215, 146, 239, 136, 29, 95, 196, 4, 84, 222, 36, 242, + 199, 67, 122, 249, 89, 70, 185, 30, 116, 123, 13, 16, 79, 117, 144, 197, 25, 11, 231, 225, + 99, 23, 226, 120, 207, 235, 52, 64, 59, 211, 62, 17, 100, 44, 153, 129, 139, 92, 133, 223, + 57, 169, 208, 256, 236, 73, 248, 68, 143, 176, 98, 2, 42, 111, 18, 121, 228, 162, 61, 253, + 173, 35, 221, 15, 58, 190, 135, 8, 168, 187, 72, 227, 141, 134, 244, 241, 178, 140, 113, 60, + 232, 246, 26, 32, 158, 234, 31, 137, 50, 22, 205, 193, 198, 46, 195, 240, 157, 213, 104, + 128, 118, 165, 124, 34, 200, 88, 49, 1, 21, 184, 9, 189, 114, 81, 159, 255, 215, 146, 239, + 136, 29, 95, 196, 4, 84, 222, 36, 242, 199, 67, 122, 249, 89, 70, 185, 30, 116, 123, 13, 16, + 79, 117, 144, 197, 25, 11, 231, 225, 99, 23, 226, 120, 207, 235, 52, 64, 59, 211, 62, 17, + 100, 44, 153, 129, 139, 92, 133, 223, 57, 169, 208, 256, 236, 73, 248, 68, 143, 176, 98, 2, + 42, 111, 18, 121, 228, 162, 61, 253, 173, 35, 221, 15, 58, 190, 135, 8, 168, 187, 72, 227, + 141, 134, 244, 241, 178, 140, 113, 60, 232, 246, 26, 32, 158, 234, 31, 137, 50, 22, 205, + 193, 198, 46, 195, 240, 157, 213, 104, 128, 118, 165, 124, 34, 200, 88, 49, 1, + ], + [ + 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, + 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, + 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, + 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, 67, 189, 46, 241, + 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, 235, 30, 146, + 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, 176, 17, 117, 4, + 88, 137, 187, 2, 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, 134, 121, 92, 225, + 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, 255, 213, 60, 35, 256, + 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, 16, 95, 34, 234, 8, + 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1, 22, 227, 111, 129, 11, 242, 184, 193, + 134, 121, 92, 225, 67, 189, 46, 241, 162, 223, 23, 249, 81, 240, 140, 253, 169, 120, 70, + 255, 213, 60, 35, 256, 235, 30, 146, 128, 246, 15, 73, 64, 123, 136, 165, 32, 190, 68, 211, + 16, 95, 34, 234, 8, 176, 17, 117, 4, 88, 137, 187, 2, 44, 197, 222, 1, + ], + [ + 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, + 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, + 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, + 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, 117, 121, 213, 16, + 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, 234, 242, 169, 32, + 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, 211, 227, 81, 64, + 187, 189, 235, 8, 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, 197, 162, 128, + 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, 137, 67, 256, + 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, 17, 134, 255, + 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1, 23, 15, 88, 225, 35, 34, 11, 253, 165, + 197, 162, 128, 117, 121, 213, 16, 111, 240, 123, 2, 46, 30, 176, 193, 70, 68, 22, 249, 73, + 137, 67, 256, 234, 242, 169, 32, 222, 223, 246, 4, 92, 60, 95, 129, 140, 136, 44, 241, 146, + 17, 134, 255, 211, 227, 81, 64, 187, 189, 235, 8, 184, 120, 190, 1, + ], + [ + 1, 24, 62, 203, 246, 250, 89, 80, 121, 77, 49, 148, 211, 181, 232, 171, 249, 65, 18, 175, + 88, 56, 59, 131, 60, 155, 122, 101, 111, 94, 200, 174, 64, 251, 113, 142, 67, 66, 42, 237, + 34, 45, 52, 220, 140, 19, 199, 150, 2, 48, 124, 149, 235, 243, 178, 160, 242, 154, 98, 39, + 165, 105, 207, 85, 241, 130, 36, 93, 176, 112, 118, 5, 120, 53, 244, 202, 222, 188, 143, 91, + 128, 245, 226, 27, 134, 132, 84, 217, 68, 90, 104, 183, 23, 38, 141, 43, 4, 96, 248, 41, + 213, 229, 99, 63, 227, 51, 196, 78, 73, 210, 157, 170, 225, 3, 72, 186, 95, 224, 236, 10, + 240, 106, 231, 147, 187, 119, 29, 182, 256, 233, 195, 54, 11, 7, 168, 177, 136, 180, 208, + 109, 46, 76, 25, 86, 8, 192, 239, 82, 169, 201, 198, 126, 197, 102, 135, 156, 146, 163, 57, + 83, 193, 6, 144, 115, 190, 191, 215, 20, 223, 212, 205, 37, 117, 238, 58, 107, 255, 209, + 133, 108, 22, 14, 79, 97, 15, 103, 159, 218, 92, 152, 50, 172, 16, 127, 221, 164, 81, 145, + 139, 252, 137, 204, 13, 55, 35, 69, 114, 166, 129, 12, 31, 230, 123, 125, 173, 40, 189, 167, + 153, 74, 234, 219, 116, 214, 253, 161, 9, 216, 44, 28, 158, 194, 30, 206, 61, 179, 184, 47, + 100, 87, 32, 254, 185, 71, 162, 33, 21, 247, 17, 151, 26, 110, 70, 138, 228, 75, 1, + ], + [ + 1, 25, 111, 205, 242, 139, 134, 9, 225, 228, 46, 122, 223, 178, 81, 226, 253, 157, 70, 208, + 60, 215, 235, 221, 128, 116, 73, 26, 136, 59, 190, 124, 16, 143, 234, 196, 17, 168, 88, 144, + 2, 50, 222, 153, 227, 21, 11, 18, 193, 199, 92, 244, 189, 99, 162, 195, 249, 57, 140, 159, + 120, 173, 213, 185, 256, 232, 146, 52, 15, 118, 123, 248, 32, 29, 211, 135, 34, 79, 176, 31, + 4, 100, 187, 49, 197, 42, 22, 36, 129, 141, 184, 231, 121, 198, 67, 133, 241, 114, 23, 61, + 240, 89, 169, 113, 255, 207, 35, 104, 30, 236, 246, 239, 64, 58, 165, 13, 68, 158, 95, 62, + 8, 200, 117, 98, 137, 84, 44, 72, 1, 25, 111, 205, 242, 139, 134, 9, 225, 228, 46, 122, 223, + 178, 81, 226, 253, 157, 70, 208, 60, 215, 235, 221, 128, 116, 73, 26, 136, 59, 190, 124, 16, + 143, 234, 196, 17, 168, 88, 144, 2, 50, 222, 153, 227, 21, 11, 18, 193, 199, 92, 244, 189, + 99, 162, 195, 249, 57, 140, 159, 120, 173, 213, 185, 256, 232, 146, 52, 15, 118, 123, 248, + 32, 29, 211, 135, 34, 79, 176, 31, 4, 100, 187, 49, 197, 42, 22, 36, 129, 141, 184, 231, + 121, 198, 67, 133, 241, 114, 23, 61, 240, 89, 169, 113, 255, 207, 35, 104, 30, 236, 246, + 239, 64, 58, 165, 13, 68, 158, 95, 62, 8, 200, 117, 98, 137, 84, 44, 72, 1, + ], + [ + 1, 26, 162, 100, 30, 9, 234, 173, 129, 13, 81, 50, 15, 133, 117, 215, 193, 135, 169, 25, + 136, 195, 187, 236, 225, 196, 213, 141, 68, 226, 222, 118, 241, 98, 235, 199, 34, 113, 111, + 59, 249, 49, 246, 228, 17, 185, 184, 158, 253, 153, 123, 114, 137, 221, 92, 79, 255, 205, + 190, 57, 197, 239, 46, 168, 256, 231, 95, 157, 227, 248, 23, 84, 128, 244, 176, 207, 242, + 124, 140, 42, 64, 122, 88, 232, 121, 62, 70, 21, 32, 61, 44, 116, 189, 31, 35, 139, 16, 159, + 22, 58, 223, 144, 146, 198, 8, 208, 11, 29, 240, 72, 73, 99, 4, 104, 134, 143, 120, 36, 165, + 178, 2, 52, 67, 200, 60, 18, 211, 89, 1, 26, 162, 100, 30, 9, 234, 173, 129, 13, 81, 50, 15, + 133, 117, 215, 193, 135, 169, 25, 136, 195, 187, 236, 225, 196, 213, 141, 68, 226, 222, 118, + 241, 98, 235, 199, 34, 113, 111, 59, 249, 49, 246, 228, 17, 185, 184, 158, 253, 153, 123, + 114, 137, 221, 92, 79, 255, 205, 190, 57, 197, 239, 46, 168, 256, 231, 95, 157, 227, 248, + 23, 84, 128, 244, 176, 207, 242, 124, 140, 42, 64, 122, 88, 232, 121, 62, 70, 21, 32, 61, + 44, 116, 189, 31, 35, 139, 16, 159, 22, 58, 223, 144, 146, 198, 8, 208, 11, 29, 240, 72, 73, + 99, 4, 104, 134, 143, 120, 36, 165, 178, 2, 52, 67, 200, 60, 18, 211, 89, 1, + ], + [ + 1, 27, 215, 151, 222, 83, 185, 112, 197, 179, 207, 192, 44, 160, 208, 219, 2, 54, 173, 45, + 187, 166, 113, 224, 137, 101, 157, 127, 88, 63, 159, 181, 4, 108, 89, 90, 117, 75, 226, 191, + 17, 202, 57, 254, 176, 126, 61, 105, 8, 216, 178, 180, 234, 150, 195, 125, 34, 147, 114, + 251, 95, 252, 122, 210, 16, 175, 99, 103, 211, 43, 133, 250, 68, 37, 228, 245, 190, 247, + 244, 163, 32, 93, 198, 206, 165, 86, 9, 243, 136, 74, 199, 233, 123, 237, 231, 69, 64, 186, + 139, 155, 73, 172, 18, 229, 15, 148, 141, 209, 246, 217, 205, 138, 128, 115, 21, 53, 146, + 87, 36, 201, 30, 39, 25, 161, 235, 177, 153, 19, 256, 230, 42, 106, 35, 174, 72, 145, 60, + 78, 50, 65, 213, 97, 49, 38, 255, 203, 84, 212, 70, 91, 144, 33, 120, 156, 100, 130, 169, + 194, 98, 76, 253, 149, 168, 167, 140, 182, 31, 66, 240, 55, 200, 3, 81, 131, 196, 152, 249, + 41, 79, 77, 23, 107, 62, 132, 223, 110, 143, 6, 162, 5, 135, 47, 241, 82, 158, 154, 46, 214, + 124, 7, 189, 220, 29, 12, 67, 10, 13, 94, 225, 164, 59, 51, 92, 171, 248, 14, 121, 183, 58, + 24, 134, 20, 26, 188, 193, 71, 118, 102, 184, 85, 239, 28, 242, 109, 116, 48, 11, 40, 52, + 119, 129, 142, 236, 204, 111, 170, 221, 56, 227, 218, 232, 96, 22, 80, 104, 238, 1, + ], + [ + 1, 28, 13, 107, 169, 106, 141, 93, 34, 181, 185, 40, 92, 6, 168, 78, 128, 243, 122, 75, 44, + 204, 58, 82, 240, 38, 36, 237, 211, 254, 173, 218, 193, 7, 196, 91, 235, 155, 228, 216, 137, + 238, 239, 10, 23, 130, 42, 148, 32, 125, 159, 83, 11, 51, 143, 149, 60, 138, 9, 252, 117, + 192, 236, 183, 241, 66, 49, 87, 123, 103, 57, 54, 227, 188, 124, 131, 70, 161, 139, 37, 8, + 224, 104, 85, 67, 77, 100, 230, 15, 163, 195, 63, 222, 48, 59, 110, 253, 145, 205, 86, 95, + 90, 207, 142, 121, 47, 31, 97, 146, 233, 99, 202, 2, 56, 26, 214, 81, 212, 25, 186, 68, 105, + 113, 80, 184, 12, 79, 156, 256, 229, 244, 150, 88, 151, 116, 164, 223, 76, 72, 217, 165, + 251, 89, 179, 129, 14, 135, 182, 213, 53, 199, 175, 17, 219, 221, 20, 46, 3, 84, 39, 64, + 250, 61, 166, 22, 102, 29, 41, 120, 19, 18, 247, 234, 127, 215, 109, 225, 132, 98, 174, 246, + 206, 114, 108, 197, 119, 248, 5, 140, 65, 21, 74, 16, 191, 208, 170, 134, 154, 200, 203, 30, + 69, 133, 126, 187, 96, 118, 220, 249, 33, 153, 172, 190, 180, 157, 27, 242, 94, 62, 194, 35, + 209, 198, 147, 4, 112, 52, 171, 162, 167, 50, 115, 136, 210, 226, 160, 111, 24, 158, 55, + 255, 201, 231, 43, 176, 45, 232, 71, 189, 152, 144, 177, 73, 245, 178, 101, 1, + ], + [ + 1, 29, 70, 231, 17, 236, 162, 72, 32, 157, 184, 196, 30, 99, 44, 248, 253, 141, 234, 104, + 189, 84, 123, 226, 129, 143, 35, 244, 137, 118, 81, 36, 16, 207, 92, 98, 15, 178, 22, 124, + 255, 199, 117, 52, 223, 42, 190, 113, 193, 200, 146, 122, 197, 59, 169, 18, 8, 232, 46, 49, + 136, 89, 11, 62, 256, 228, 187, 26, 240, 21, 95, 185, 225, 100, 73, 61, 227, 158, 213, 9, 4, + 116, 23, 153, 68, 173, 134, 31, 128, 114, 222, 13, 120, 139, 176, 221, 241, 50, 165, 159, + 242, 79, 235, 133, 2, 58, 140, 205, 34, 215, 67, 144, 64, 57, 111, 135, 60, 198, 88, 239, + 249, 25, 211, 208, 121, 168, 246, 195, 1, 29, 70, 231, 17, 236, 162, 72, 32, 157, 184, 196, + 30, 99, 44, 248, 253, 141, 234, 104, 189, 84, 123, 226, 129, 143, 35, 244, 137, 118, 81, 36, + 16, 207, 92, 98, 15, 178, 22, 124, 255, 199, 117, 52, 223, 42, 190, 113, 193, 200, 146, 122, + 197, 59, 169, 18, 8, 232, 46, 49, 136, 89, 11, 62, 256, 228, 187, 26, 240, 21, 95, 185, 225, + 100, 73, 61, 227, 158, 213, 9, 4, 116, 23, 153, 68, 173, 134, 31, 128, 114, 222, 13, 120, + 139, 176, 221, 241, 50, 165, 159, 242, 79, 235, 133, 2, 58, 140, 205, 34, 215, 67, 144, 64, + 57, 111, 135, 60, 198, 88, 239, 249, 25, 211, 208, 121, 168, 246, 195, 1, + ], + [ + 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, + 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, + 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, + 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, + 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, + 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, + 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, + 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, + 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, + 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, + 17, 253, 137, 255, 197, 256, 227, 128, 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, + 60, 1, 30, 129, 15, 193, 136, 225, 68, 241, 34, 249, 17, 253, 137, 255, 197, 256, 227, 128, + 242, 64, 121, 32, 189, 16, 223, 8, 240, 4, 120, 2, 60, 1, + ], + [ + 1, 31, 190, 236, 120, 122, 184, 50, 8, 248, 235, 89, 189, 205, 187, 143, 64, 185, 81, 198, + 227, 98, 211, 116, 255, 195, 134, 42, 17, 13, 146, 157, 241, 18, 44, 79, 136, 104, 140, 228, + 129, 144, 95, 118, 60, 61, 92, 25, 4, 124, 246, 173, 223, 231, 222, 200, 32, 221, 169, 99, + 242, 49, 234, 58, 256, 226, 67, 21, 137, 135, 73, 207, 249, 9, 22, 168, 68, 52, 70, 114, + 193, 72, 176, 59, 30, 159, 46, 141, 2, 62, 123, 215, 240, 244, 111, 100, 16, 239, 213, 178, + 121, 153, 117, 29, 128, 113, 162, 139, 197, 196, 165, 232, 253, 133, 11, 84, 34, 26, 35, 57, + 225, 36, 88, 158, 15, 208, 23, 199, 1, 31, 190, 236, 120, 122, 184, 50, 8, 248, 235, 89, + 189, 205, 187, 143, 64, 185, 81, 198, 227, 98, 211, 116, 255, 195, 134, 42, 17, 13, 146, + 157, 241, 18, 44, 79, 136, 104, 140, 228, 129, 144, 95, 118, 60, 61, 92, 25, 4, 124, 246, + 173, 223, 231, 222, 200, 32, 221, 169, 99, 242, 49, 234, 58, 256, 226, 67, 21, 137, 135, 73, + 207, 249, 9, 22, 168, 68, 52, 70, 114, 193, 72, 176, 59, 30, 159, 46, 141, 2, 62, 123, 215, + 240, 244, 111, 100, 16, 239, 213, 178, 121, 153, 117, 29, 128, 113, 162, 139, 197, 196, 165, + 232, 253, 133, 11, 84, 34, 26, 35, 57, 225, 36, 88, 158, 15, 208, 23, 199, 1, + ], + [ + 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, + 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, + 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, + 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, + 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, + 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, + 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, + 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, + 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, + 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, + 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, + 256, 225, 4, 128, 241, 2, 64, 249, 1, 32, 253, 129, 16, 255, 193, 8, 256, 225, 4, 128, 241, + 2, 64, 249, 1, + ], + [ + 1, 33, 61, 214, 123, 204, 50, 108, 223, 163, 239, 177, 187, 3, 99, 183, 128, 112, 98, 150, + 67, 155, 232, 203, 17, 47, 9, 40, 35, 127, 79, 37, 193, 201, 208, 182, 95, 51, 141, 27, 120, + 105, 124, 237, 111, 65, 89, 110, 32, 28, 153, 166, 81, 103, 58, 115, 197, 76, 195, 10, 73, + 96, 84, 202, 241, 243, 52, 174, 88, 77, 228, 71, 30, 219, 31, 252, 92, 209, 215, 156, 8, 7, + 231, 170, 213, 90, 143, 93, 242, 19, 113, 131, 211, 24, 21, 179, 253, 125, 13, 172, 22, 212, + 57, 82, 136, 119, 72, 63, 23, 245, 118, 39, 2, 66, 122, 171, 246, 151, 100, 216, 189, 69, + 221, 97, 117, 6, 198, 109, 256, 224, 196, 43, 134, 53, 207, 149, 34, 94, 18, 80, 70, 254, + 158, 74, 129, 145, 159, 107, 190, 102, 25, 54, 240, 210, 248, 217, 222, 130, 178, 220, 64, + 56, 49, 75, 162, 206, 116, 230, 137, 152, 133, 20, 146, 192, 168, 147, 225, 229, 104, 91, + 176, 154, 199, 142, 60, 181, 62, 247, 184, 161, 173, 55, 16, 14, 205, 83, 169, 180, 29, 186, + 227, 38, 226, 5, 165, 48, 42, 101, 249, 250, 26, 87, 44, 167, 114, 164, 15, 238, 144, 126, + 46, 233, 236, 78, 4, 132, 244, 85, 235, 45, 200, 175, 121, 138, 185, 194, 234, 12, 139, 218, + 255, 191, 135, 86, 11, 106, 157, 41, 68, 188, 36, 160, 140, 251, 59, 148, 1, + ], + [ + 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, + 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, + 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, + 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, + 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, + 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, + 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, + 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, + 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, + 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, + 121, 2, 68, 256, 223, 129, 17, 64, 120, 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, 34, + 128, 240, 193, 137, 32, 60, 241, 227, 8, 15, 253, 121, 2, 68, 256, 223, 129, 17, 64, 120, + 225, 197, 16, 30, 249, 242, 4, 136, 255, 189, 1, + ], + [ + 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, + 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, + 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, + 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, 162, 16, 46, 68, + 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, 255, 187, 120, + 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, 123, 193, 73, + 242, 246, 129, 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, 81, 8, 23, 34, + 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, 256, 222, 60, 44, + 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, 190, 225, 165, 121, + 123, 193, 73, 242, 246, 129, 146, 227, 235, 1, 35, 197, 213, 2, 70, 137, 169, 4, 140, 17, + 81, 8, 23, 34, 162, 16, 46, 68, 67, 32, 92, 136, 134, 64, 184, 15, 11, 128, 111, 30, 22, + 256, 222, 60, 44, 255, 187, 120, 88, 253, 117, 240, 176, 249, 234, 223, 95, 241, 211, 189, + 190, 225, 165, 121, 123, 193, 73, 242, 246, 129, 146, 227, 235, 1, + ], + [ + 1, 36, 11, 139, 121, 244, 46, 114, 249, 226, 169, 173, 60, 104, 146, 116, 64, 248, 190, 158, + 34, 196, 117, 100, 2, 72, 22, 21, 242, 231, 92, 228, 241, 195, 81, 89, 120, 208, 35, 232, + 128, 239, 123, 59, 68, 135, 234, 200, 4, 144, 44, 42, 227, 205, 184, 199, 225, 133, 162, + 178, 240, 159, 70, 207, 256, 221, 246, 118, 136, 13, 211, 143, 8, 31, 88, 84, 197, 153, 111, + 141, 193, 9, 67, 99, 223, 61, 140, 157, 255, 185, 235, 236, 15, 26, 165, 29, 16, 62, 176, + 168, 137, 49, 222, 25, 129, 18, 134, 198, 189, 122, 23, 57, 253, 113, 213, 215, 30, 52, 73, + 58, 32, 124, 95, 79, 17, 98, 187, 50, 1, 36, 11, 139, 121, 244, 46, 114, 249, 226, 169, 173, + 60, 104, 146, 116, 64, 248, 190, 158, 34, 196, 117, 100, 2, 72, 22, 21, 242, 231, 92, 228, + 241, 195, 81, 89, 120, 208, 35, 232, 128, 239, 123, 59, 68, 135, 234, 200, 4, 144, 44, 42, + 227, 205, 184, 199, 225, 133, 162, 178, 240, 159, 70, 207, 256, 221, 246, 118, 136, 13, 211, + 143, 8, 31, 88, 84, 197, 153, 111, 141, 193, 9, 67, 99, 223, 61, 140, 157, 255, 185, 235, + 236, 15, 26, 165, 29, 16, 62, 176, 168, 137, 49, 222, 25, 129, 18, 134, 198, 189, 122, 23, + 57, 253, 113, 213, 215, 30, 52, 73, 58, 32, 124, 95, 79, 17, 98, 187, 50, 1, + ], + [ + 1, 37, 84, 24, 117, 217, 62, 238, 68, 203, 58, 90, 246, 107, 104, 250, 255, 183, 89, 209, + 23, 80, 133, 38, 121, 108, 141, 77, 22, 43, 49, 14, 4, 148, 79, 96, 211, 97, 248, 181, 15, + 41, 232, 103, 213, 171, 159, 229, 249, 218, 99, 65, 92, 63, 18, 152, 227, 175, 50, 51, 88, + 172, 196, 56, 16, 78, 59, 127, 73, 131, 221, 210, 60, 164, 157, 155, 81, 170, 122, 145, 225, + 101, 139, 3, 111, 252, 72, 94, 137, 186, 200, 204, 95, 174, 13, 224, 64, 55, 236, 251, 35, + 10, 113, 69, 240, 142, 114, 106, 67, 166, 231, 66, 129, 147, 42, 12, 187, 237, 31, 119, 34, + 230, 29, 45, 123, 182, 52, 125, 256, 220, 173, 233, 140, 40, 195, 19, 189, 54, 199, 167, 11, + 150, 153, 7, 2, 74, 168, 48, 234, 177, 124, 219, 136, 149, 116, 180, 235, 214, 208, 243, + 253, 109, 178, 161, 46, 160, 9, 76, 242, 216, 25, 154, 44, 86, 98, 28, 8, 39, 158, 192, 165, + 194, 239, 105, 30, 82, 207, 206, 169, 85, 61, 201, 241, 179, 198, 130, 184, 126, 36, 47, + 197, 93, 100, 102, 176, 87, 135, 112, 32, 156, 118, 254, 146, 5, 185, 163, 120, 71, 57, 53, + 162, 83, 244, 33, 193, 202, 21, 6, 222, 247, 144, 188, 17, 115, 143, 151, 190, 91, 26, 191, + 128, 110, 215, 245, 70, 20, 226, 138, 223, 27, 228, 212, 134, 75, 205, 132, 1, + ], + [ + 1, 38, 159, 131, 95, 12, 199, 109, 30, 112, 144, 75, 23, 103, 59, 186, 129, 19, 208, 194, + 176, 6, 228, 183, 15, 56, 72, 166, 140, 180, 158, 93, 193, 138, 104, 97, 88, 3, 114, 220, + 136, 28, 36, 83, 70, 90, 79, 175, 225, 69, 52, 177, 44, 130, 57, 110, 68, 14, 18, 170, 35, + 45, 168, 216, 241, 163, 26, 217, 22, 65, 157, 55, 34, 7, 9, 85, 146, 151, 84, 108, 249, 210, + 13, 237, 11, 161, 207, 156, 17, 132, 133, 171, 73, 204, 42, 54, 253, 105, 135, 247, 134, + 209, 232, 78, 137, 66, 195, 214, 165, 102, 21, 27, 255, 181, 196, 252, 67, 233, 116, 39, + 197, 33, 226, 107, 211, 51, 139, 142, 256, 219, 98, 126, 162, 245, 58, 148, 227, 145, 113, + 182, 234, 154, 198, 71, 128, 238, 49, 63, 81, 251, 29, 74, 242, 201, 185, 91, 117, 77, 99, + 164, 64, 119, 153, 160, 169, 254, 143, 37, 121, 229, 221, 174, 187, 167, 178, 82, 32, 188, + 205, 80, 213, 127, 200, 147, 189, 243, 239, 87, 222, 212, 89, 41, 16, 94, 231, 40, 235, 192, + 100, 202, 223, 250, 248, 172, 111, 106, 173, 149, 8, 47, 244, 20, 246, 96, 50, 101, 240, + 125, 124, 86, 184, 53, 215, 203, 4, 152, 122, 10, 123, 48, 25, 179, 120, 191, 62, 43, 92, + 155, 236, 230, 2, 76, 61, 5, 190, 24, 141, 218, 60, 224, 31, 150, 46, 206, 118, 115, 1, + ], + [ + 1, 39, 236, 209, 184, 237, 248, 163, 189, 175, 143, 180, 81, 75, 98, 224, 255, 179, 42, 96, + 146, 40, 18, 188, 136, 164, 228, 154, 95, 107, 61, 66, 4, 156, 173, 65, 222, 177, 221, 138, + 242, 186, 58, 206, 67, 43, 135, 125, 249, 202, 168, 127, 70, 160, 72, 238, 30, 142, 141, + 102, 123, 171, 244, 7, 16, 110, 178, 3, 117, 194, 113, 38, 197, 230, 232, 53, 11, 172, 26, + 243, 225, 37, 158, 251, 23, 126, 31, 181, 120, 54, 50, 151, 235, 170, 205, 28, 64, 183, 198, + 12, 211, 5, 195, 152, 17, 149, 157, 212, 44, 174, 104, 201, 129, 148, 118, 233, 92, 247, + 124, 210, 223, 216, 200, 90, 169, 166, 49, 112, 256, 218, 21, 48, 73, 20, 9, 94, 68, 82, + 114, 77, 176, 182, 159, 33, 2, 78, 215, 161, 111, 217, 239, 69, 121, 93, 29, 103, 162, 150, + 196, 191, 253, 101, 84, 192, 35, 80, 36, 119, 15, 71, 199, 51, 190, 214, 122, 132, 8, 55, + 89, 130, 187, 97, 185, 19, 227, 115, 116, 155, 134, 86, 13, 250, 241, 147, 79, 254, 140, 63, + 144, 219, 60, 27, 25, 204, 246, 85, 231, 14, 32, 220, 99, 6, 234, 131, 226, 76, 137, 203, + 207, 106, 22, 87, 52, 229, 193, 74, 59, 245, 46, 252, 62, 105, 240, 108, 100, 45, 213, 83, + 153, 56, 128, 109, 139, 24, 165, 10, 133, 47, 34, 41, 57, 167, 88, 91, 208, 145, 1, + ], + [ + 1, 40, 58, 7, 23, 149, 49, 161, 15, 86, 99, 105, 88, 179, 221, 102, 225, 5, 200, 33, 35, + 115, 231, 245, 34, 75, 173, 238, 11, 183, 124, 77, 253, 97, 25, 229, 165, 175, 61, 127, 197, + 170, 118, 94, 162, 55, 144, 106, 128, 237, 228, 125, 117, 54, 104, 48, 121, 214, 79, 76, + 213, 39, 18, 206, 16, 126, 157, 112, 111, 71, 13, 6, 240, 91, 42, 138, 123, 37, 195, 90, 2, + 80, 116, 14, 46, 41, 98, 65, 30, 172, 198, 210, 176, 101, 185, 204, 193, 10, 143, 66, 70, + 230, 205, 233, 68, 150, 89, 219, 22, 109, 248, 154, 249, 194, 50, 201, 73, 93, 122, 254, + 137, 83, 236, 188, 67, 110, 31, 212, 256, 217, 199, 250, 234, 108, 208, 96, 242, 171, 158, + 152, 169, 78, 36, 155, 32, 252, 57, 224, 222, 142, 26, 12, 223, 182, 84, 19, 246, 74, 133, + 180, 4, 160, 232, 28, 92, 82, 196, 130, 60, 87, 139, 163, 95, 202, 113, 151, 129, 20, 29, + 132, 140, 203, 153, 209, 136, 43, 178, 181, 44, 218, 239, 51, 241, 131, 100, 145, 146, 186, + 244, 251, 17, 166, 215, 119, 134, 220, 62, 167, 255, 177, 141, 243, 211, 216, 159, 192, 227, + 85, 59, 47, 81, 156, 72, 53, 64, 247, 114, 191, 187, 27, 52, 24, 189, 107, 168, 38, 235, + 148, 9, 103, 8, 63, 207, 56, 184, 164, 135, 3, 120, 174, 21, 69, 190, 147, 226, 45, 1, + ], + [ + 1, 41, 139, 45, 46, 87, 226, 14, 60, 147, 116, 130, 190, 80, 196, 69, 2, 82, 21, 90, 92, + 174, 195, 28, 120, 37, 232, 3, 123, 160, 135, 138, 4, 164, 42, 180, 184, 91, 133, 56, 240, + 74, 207, 6, 246, 63, 13, 19, 8, 71, 84, 103, 111, 182, 9, 112, 223, 148, 157, 12, 235, 126, + 26, 38, 16, 142, 168, 206, 222, 107, 18, 224, 189, 39, 57, 24, 213, 252, 52, 76, 32, 27, 79, + 155, 187, 214, 36, 191, 121, 78, 114, 48, 169, 247, 104, 152, 64, 54, 158, 53, 117, 171, 72, + 125, 242, 156, 228, 96, 81, 237, 208, 47, 128, 108, 59, 106, 234, 85, 144, 250, 227, 55, + 199, 192, 162, 217, 159, 94, 256, 216, 118, 212, 211, 170, 31, 243, 197, 110, 141, 127, 67, + 177, 61, 188, 255, 175, 236, 167, 165, 83, 62, 229, 137, 220, 25, 254, 134, 97, 122, 119, + 253, 93, 215, 77, 73, 166, 124, 201, 17, 183, 50, 251, 11, 194, 244, 238, 249, 186, 173, + 154, 146, 75, 248, 145, 34, 109, 100, 245, 22, 131, 231, 219, 241, 115, 89, 51, 35, 150, + 239, 33, 68, 218, 200, 233, 44, 5, 205, 181, 225, 230, 178, 102, 70, 43, 221, 66, 136, 179, + 143, 209, 88, 10, 153, 105, 193, 203, 99, 204, 140, 86, 185, 132, 15, 101, 29, 161, 176, 20, + 49, 210, 129, 149, 198, 151, 23, 172, 113, 7, 30, 202, 58, 65, 95, 40, 98, 163, 1, + ], + [ + 1, 42, 222, 72, 197, 50, 44, 49, 2, 84, 187, 144, 137, 100, 88, 98, 4, 168, 117, 31, 17, + 200, 176, 196, 8, 79, 234, 62, 34, 143, 95, 135, 16, 158, 211, 124, 68, 29, 190, 13, 32, 59, + 165, 248, 136, 58, 123, 26, 64, 118, 73, 239, 15, 116, 246, 52, 128, 236, 146, 221, 30, 232, + 235, 104, 256, 215, 35, 185, 60, 207, 213, 208, 255, 173, 70, 113, 120, 157, 169, 159, 253, + 89, 140, 226, 240, 57, 81, 61, 249, 178, 23, 195, 223, 114, 162, 122, 241, 99, 46, 133, 189, + 228, 67, 244, 225, 198, 92, 9, 121, 199, 134, 231, 193, 139, 184, 18, 242, 141, 11, 205, + 129, 21, 111, 36, 227, 25, 22, 153, 1, 42, 222, 72, 197, 50, 44, 49, 2, 84, 187, 144, 137, + 100, 88, 98, 4, 168, 117, 31, 17, 200, 176, 196, 8, 79, 234, 62, 34, 143, 95, 135, 16, 158, + 211, 124, 68, 29, 190, 13, 32, 59, 165, 248, 136, 58, 123, 26, 64, 118, 73, 239, 15, 116, + 246, 52, 128, 236, 146, 221, 30, 232, 235, 104, 256, 215, 35, 185, 60, 207, 213, 208, 255, + 173, 70, 113, 120, 157, 169, 159, 253, 89, 140, 226, 240, 57, 81, 61, 249, 178, 23, 195, + 223, 114, 162, 122, 241, 99, 46, 133, 189, 228, 67, 244, 225, 198, 92, 9, 121, 199, 134, + 231, 193, 139, 184, 18, 242, 141, 11, 205, 129, 21, 111, 36, 227, 25, 22, 153, 1, + ], + [ + 1, 43, 50, 94, 187, 74, 98, 102, 17, 217, 79, 56, 95, 230, 124, 192, 32, 91, 58, 181, 73, + 55, 52, 180, 30, 5, 215, 250, 213, 164, 113, 233, 253, 85, 57, 138, 23, 218, 122, 106, 189, + 160, 198, 33, 134, 108, 18, 3, 129, 150, 25, 47, 222, 37, 49, 51, 137, 237, 168, 28, 176, + 115, 62, 96, 16, 174, 29, 219, 165, 156, 26, 90, 15, 131, 236, 125, 235, 82, 185, 245, 255, + 171, 157, 69, 140, 109, 61, 53, 223, 80, 99, 145, 67, 54, 9, 130, 193, 75, 141, 152, 111, + 147, 153, 154, 197, 247, 84, 14, 88, 186, 31, 48, 8, 87, 143, 238, 211, 78, 13, 45, 136, + 194, 118, 191, 246, 41, 221, 251, 256, 214, 207, 163, 70, 183, 159, 155, 240, 40, 178, 201, + 162, 27, 133, 65, 225, 166, 199, 76, 184, 202, 205, 77, 227, 252, 42, 7, 44, 93, 144, 24, 4, + 172, 200, 119, 234, 39, 135, 151, 68, 97, 59, 224, 123, 149, 239, 254, 128, 107, 232, 210, + 35, 220, 208, 206, 120, 20, 89, 229, 81, 142, 195, 161, 241, 83, 228, 38, 92, 101, 231, 167, + 242, 126, 21, 132, 22, 175, 72, 12, 2, 86, 100, 188, 117, 148, 196, 204, 34, 177, 158, 112, + 190, 203, 248, 127, 64, 182, 116, 105, 146, 110, 104, 103, 60, 10, 173, 243, 169, 71, 226, + 209, 249, 170, 114, 19, 46, 179, 244, 212, 121, 63, 139, 66, 11, 216, 36, 6, 1, + ], + [ + 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, + 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, + 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, + 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, 240, 23, 241, 67, + 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, 120, 140, 249, + 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, 60, 70, 253, + 81, 223, 46, 225, 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, 35, 255, 169, + 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, 146, 256, 213, + 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, 73, 128, 235, + 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1, 44, 137, 117, 8, 95, 68, 165, 64, 246, 30, + 35, 255, 169, 240, 23, 241, 67, 121, 184, 129, 22, 197, 187, 4, 176, 34, 211, 32, 123, 15, + 146, 256, 213, 120, 140, 249, 162, 189, 92, 193, 11, 227, 222, 2, 88, 17, 234, 16, 190, 136, + 73, 128, 235, 60, 70, 253, 81, 223, 46, 225, 134, 242, 111, 1, + ], + [ + 1, 45, 226, 147, 190, 69, 21, 174, 120, 3, 135, 164, 184, 56, 207, 63, 8, 103, 9, 148, 235, + 38, 168, 107, 189, 24, 52, 27, 187, 191, 114, 247, 64, 53, 72, 156, 81, 47, 59, 85, 227, + 192, 159, 216, 211, 243, 141, 177, 255, 167, 62, 220, 134, 119, 215, 166, 17, 251, 244, 186, + 146, 145, 100, 131, 241, 51, 239, 218, 44, 181, 178, 43, 136, 209, 153, 203, 140, 132, 29, + 20, 129, 151, 113, 202, 95, 163, 139, 87, 60, 130, 196, 82, 92, 28, 232, 160, 4, 180, 133, + 74, 246, 19, 84, 182, 223, 12, 26, 142, 222, 224, 57, 252, 32, 155, 36, 78, 169, 152, 158, + 171, 242, 96, 208, 108, 234, 250, 199, 217, 256, 212, 31, 110, 67, 188, 236, 83, 137, 254, + 122, 93, 73, 201, 50, 194, 249, 154, 248, 109, 22, 219, 89, 150, 68, 233, 205, 230, 70, 66, + 143, 10, 193, 204, 185, 101, 176, 210, 198, 172, 30, 65, 98, 41, 46, 14, 116, 80, 2, 90, + 195, 37, 123, 138, 42, 91, 240, 6, 13, 71, 111, 112, 157, 126, 16, 206, 18, 39, 213, 76, 79, + 214, 121, 48, 104, 54, 117, 125, 228, 237, 128, 106, 144, 55, 162, 94, 118, 170, 197, 127, + 61, 175, 165, 229, 25, 97, 253, 77, 124, 183, 11, 238, 173, 75, 34, 245, 231, 115, 35, 33, + 200, 5, 225, 102, 221, 179, 88, 105, 99, 86, 15, 161, 49, 149, 23, 7, 58, 40, 1, + ], + [ + 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, + 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, + 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, + 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, 111, 223, 235, 16, + 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, 256, 211, 197, 67, + 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, 225, 70, 136, 88, + 193, 140, 15, 176, 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, 184, 240, 246, 8, + 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, 128, 234, 227, 162, + 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, 22, 241, 35, 68, 44, + 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1, 46, 60, 190, 2, 92, 120, 123, 4, + 184, 240, 246, 8, 111, 223, 235, 16, 222, 189, 213, 32, 187, 121, 169, 64, 117, 242, 81, + 128, 234, 227, 162, 256, 211, 197, 67, 255, 165, 137, 134, 253, 73, 17, 11, 249, 146, 34, + 22, 241, 35, 68, 44, 225, 70, 136, 88, 193, 140, 15, 176, 129, 23, 30, 95, 1, + ], + [ + 1, 47, 153, 252, 22, 6, 25, 147, 227, 132, 36, 150, 111, 77, 21, 216, 129, 152, 205, 126, + 11, 3, 141, 202, 242, 66, 18, 75, 184, 167, 139, 108, 193, 76, 231, 63, 134, 130, 199, 101, + 121, 33, 9, 166, 92, 212, 198, 54, 225, 38, 244, 160, 67, 65, 228, 179, 189, 145, 133, 83, + 46, 106, 99, 27, 241, 19, 122, 80, 162, 161, 114, 218, 223, 201, 195, 170, 23, 53, 178, 142, + 249, 138, 61, 40, 81, 209, 57, 109, 240, 229, 226, 85, 140, 155, 89, 71, 253, 69, 159, 20, + 169, 233, 157, 183, 120, 243, 113, 171, 70, 206, 173, 164, 255, 163, 208, 10, 213, 245, 207, + 220, 60, 250, 185, 214, 35, 103, 215, 82, 256, 210, 104, 5, 235, 251, 232, 110, 30, 125, + 221, 107, 146, 180, 236, 41, 128, 105, 52, 131, 246, 254, 116, 55, 15, 191, 239, 182, 73, + 90, 118, 149, 64, 181, 26, 194, 123, 127, 58, 156, 136, 224, 248, 91, 165, 45, 59, 203, 32, + 219, 13, 97, 190, 192, 29, 78, 68, 112, 124, 174, 211, 151, 158, 230, 16, 238, 135, 177, 95, + 96, 143, 39, 34, 56, 62, 87, 234, 204, 79, 115, 8, 119, 196, 217, 176, 48, 200, 148, 17, 28, + 31, 172, 117, 102, 168, 186, 4, 188, 98, 237, 88, 24, 100, 74, 137, 14, 144, 86, 187, 51, + 84, 93, 2, 94, 49, 247, 44, 12, 50, 37, 197, 7, 72, 43, 222, 154, 42, 175, 1, + ], + [ + 1, 48, 248, 82, 81, 33, 42, 217, 136, 103, 61, 101, 222, 119, 58, 214, 249, 130, 72, 115, + 123, 250, 178, 63, 197, 204, 26, 220, 23, 76, 50, 87, 64, 245, 195, 108, 44, 56, 118, 10, + 223, 167, 49, 39, 73, 163, 114, 75, 2, 96, 239, 164, 162, 66, 84, 177, 15, 206, 122, 202, + 187, 238, 116, 171, 241, 3, 144, 230, 246, 243, 99, 126, 137, 151, 52, 183, 46, 152, 100, + 174, 128, 233, 133, 216, 88, 112, 236, 20, 189, 77, 98, 78, 146, 69, 228, 150, 4, 192, 221, + 71, 67, 132, 168, 97, 30, 155, 244, 147, 117, 219, 232, 85, 225, 6, 31, 203, 235, 229, 198, + 252, 17, 45, 104, 109, 92, 47, 200, 91, 256, 209, 9, 175, 176, 224, 215, 40, 121, 154, 196, + 156, 35, 138, 199, 43, 8, 127, 185, 142, 134, 7, 79, 194, 60, 53, 231, 37, 234, 181, 207, + 170, 193, 12, 62, 149, 213, 201, 139, 247, 34, 90, 208, 218, 184, 94, 143, 182, 255, 161, + 18, 93, 95, 191, 173, 80, 242, 51, 135, 55, 70, 19, 141, 86, 16, 254, 113, 27, 11, 14, 158, + 131, 120, 106, 205, 74, 211, 105, 157, 83, 129, 24, 124, 41, 169, 145, 21, 237, 68, 180, + 159, 179, 111, 188, 29, 107, 253, 65, 36, 186, 190, 125, 89, 160, 227, 102, 13, 110, 140, + 38, 25, 172, 32, 251, 226, 54, 22, 28, 59, 5, 240, 212, 153, 148, 165, 210, 57, 166, 1, + ], + [ + 1, 49, 88, 200, 34, 124, 165, 118, 128, 104, 213, 157, 240, 195, 46, 198, 193, 205, 22, 50, + 137, 31, 234, 158, 32, 26, 246, 232, 60, 113, 140, 178, 241, 244, 134, 141, 227, 72, 187, + 168, 8, 135, 190, 58, 15, 221, 35, 173, 253, 61, 162, 228, 121, 18, 111, 42, 2, 98, 176, + 143, 68, 248, 73, 236, 256, 208, 169, 57, 223, 133, 92, 139, 129, 153, 44, 100, 17, 62, 211, + 59, 64, 52, 235, 207, 120, 226, 23, 99, 225, 231, 11, 25, 197, 144, 117, 79, 16, 13, 123, + 116, 30, 185, 70, 89, 249, 122, 67, 199, 242, 36, 222, 84, 4, 196, 95, 29, 136, 239, 146, + 215, 255, 159, 81, 114, 189, 9, 184, 21, 1, 49, 88, 200, 34, 124, 165, 118, 128, 104, 213, + 157, 240, 195, 46, 198, 193, 205, 22, 50, 137, 31, 234, 158, 32, 26, 246, 232, 60, 113, 140, + 178, 241, 244, 134, 141, 227, 72, 187, 168, 8, 135, 190, 58, 15, 221, 35, 173, 253, 61, 162, + 228, 121, 18, 111, 42, 2, 98, 176, 143, 68, 248, 73, 236, 256, 208, 169, 57, 223, 133, 92, + 139, 129, 153, 44, 100, 17, 62, 211, 59, 64, 52, 235, 207, 120, 226, 23, 99, 225, 231, 11, + 25, 197, 144, 117, 79, 16, 13, 123, 116, 30, 185, 70, 89, 249, 122, 67, 199, 242, 36, 222, + 84, 4, 196, 95, 29, 136, 239, 146, 215, 255, 159, 81, 114, 189, 9, 184, 21, 1, + ], + [ + 1, 50, 187, 98, 17, 79, 95, 124, 32, 58, 73, 52, 30, 215, 213, 113, 253, 57, 23, 122, 189, + 198, 134, 18, 129, 25, 222, 49, 137, 168, 176, 62, 16, 29, 165, 26, 15, 236, 235, 185, 255, + 157, 140, 61, 223, 99, 67, 9, 193, 141, 111, 153, 197, 84, 88, 31, 8, 143, 211, 13, 136, + 118, 246, 221, 256, 207, 70, 159, 240, 178, 162, 133, 225, 199, 184, 205, 227, 42, 44, 144, + 4, 200, 234, 135, 68, 59, 123, 239, 128, 232, 35, 208, 120, 89, 81, 195, 241, 228, 92, 231, + 242, 21, 22, 72, 2, 100, 117, 196, 34, 158, 190, 248, 64, 116, 146, 104, 60, 173, 169, 226, + 249, 114, 46, 244, 121, 139, 11, 36, 1, 50, 187, 98, 17, 79, 95, 124, 32, 58, 73, 52, 30, + 215, 213, 113, 253, 57, 23, 122, 189, 198, 134, 18, 129, 25, 222, 49, 137, 168, 176, 62, 16, + 29, 165, 26, 15, 236, 235, 185, 255, 157, 140, 61, 223, 99, 67, 9, 193, 141, 111, 153, 197, + 84, 88, 31, 8, 143, 211, 13, 136, 118, 246, 221, 256, 207, 70, 159, 240, 178, 162, 133, 225, + 199, 184, 205, 227, 42, 44, 144, 4, 200, 234, 135, 68, 59, 123, 239, 128, 232, 35, 208, 120, + 89, 81, 195, 241, 228, 92, 231, 242, 21, 22, 72, 2, 100, 117, 196, 34, 158, 190, 248, 64, + 116, 146, 104, 60, 173, 169, 226, 249, 114, 46, 244, 121, 139, 11, 36, 1, + ], + [ + 1, 51, 31, 39, 190, 181, 236, 214, 120, 209, 122, 54, 184, 132, 50, 237, 8, 151, 248, 55, + 235, 163, 89, 170, 189, 130, 205, 175, 187, 28, 143, 97, 64, 180, 185, 183, 81, 19, 198, 75, + 227, 12, 98, 115, 211, 224, 116, 5, 255, 155, 195, 179, 134, 152, 42, 86, 17, 96, 13, 149, + 146, 250, 157, 40, 241, 212, 18, 147, 44, 188, 79, 174, 136, 254, 104, 164, 140, 201, 228, + 63, 129, 154, 144, 148, 95, 219, 118, 107, 60, 233, 61, 27, 92, 66, 25, 247, 4, 204, 124, + 156, 246, 210, 173, 85, 223, 65, 231, 216, 222, 14, 200, 177, 32, 90, 221, 220, 169, 138, + 99, 166, 242, 6, 49, 186, 234, 112, 58, 131, 256, 206, 226, 218, 67, 76, 21, 43, 137, 48, + 135, 203, 73, 125, 207, 20, 249, 106, 9, 202, 22, 94, 168, 87, 68, 127, 52, 82, 70, 229, + 114, 160, 193, 77, 72, 74, 176, 238, 59, 182, 30, 245, 159, 142, 46, 33, 141, 252, 2, 102, + 62, 78, 123, 105, 215, 171, 240, 161, 244, 108, 111, 7, 100, 217, 16, 45, 239, 110, 213, 69, + 178, 83, 121, 3, 153, 93, 117, 56, 29, 194, 128, 103, 113, 109, 162, 38, 139, 150, 197, 24, + 196, 230, 165, 191, 232, 10, 253, 53, 133, 101, 11, 47, 84, 172, 34, 192, 26, 41, 35, 243, + 57, 80, 225, 167, 36, 37, 88, 119, 158, 91, 15, 251, 208, 71, 23, 145, 199, 126, 1, + ], + [ + 1, 52, 134, 29, 223, 31, 70, 42, 128, 231, 190, 114, 17, 113, 222, 236, 193, 13, 162, 200, + 120, 72, 146, 139, 32, 122, 176, 157, 197, 221, 184, 59, 241, 196, 169, 50, 30, 18, 165, 99, + 8, 159, 44, 232, 242, 248, 46, 79, 253, 49, 235, 141, 136, 133, 234, 89, 2, 104, 11, 58, + 189, 62, 140, 84, 256, 205, 123, 228, 34, 226, 187, 215, 129, 26, 67, 143, 240, 144, 35, 21, + 64, 244, 95, 57, 137, 185, 111, 118, 225, 135, 81, 100, 60, 36, 73, 198, 16, 61, 88, 207, + 227, 239, 92, 158, 249, 98, 213, 25, 15, 9, 211, 178, 4, 208, 22, 116, 121, 124, 23, 168, + 255, 153, 246, 199, 68, 195, 117, 173, 1, 52, 134, 29, 223, 31, 70, 42, 128, 231, 190, 114, + 17, 113, 222, 236, 193, 13, 162, 200, 120, 72, 146, 139, 32, 122, 176, 157, 197, 221, 184, + 59, 241, 196, 169, 50, 30, 18, 165, 99, 8, 159, 44, 232, 242, 248, 46, 79, 253, 49, 235, + 141, 136, 133, 234, 89, 2, 104, 11, 58, 189, 62, 140, 84, 256, 205, 123, 228, 34, 226, 187, + 215, 129, 26, 67, 143, 240, 144, 35, 21, 64, 244, 95, 57, 137, 185, 111, 118, 225, 135, 81, + 100, 60, 36, 73, 198, 16, 61, 88, 207, 227, 239, 92, 158, 249, 98, 213, 25, 15, 9, 211, 178, + 4, 208, 22, 116, 121, 124, 23, 168, 255, 153, 246, 199, 68, 195, 117, 173, 1, + ], + [ + 1, 53, 239, 74, 67, 210, 79, 75, 120, 192, 153, 142, 73, 14, 228, 5, 8, 167, 113, 78, 22, + 138, 118, 86, 189, 251, 196, 108, 70, 112, 25, 40, 64, 51, 133, 110, 176, 76, 173, 174, 227, + 209, 26, 93, 46, 125, 200, 63, 255, 151, 36, 109, 123, 94, 99, 107, 17, 130, 208, 230, 111, + 229, 58, 247, 241, 180, 31, 101, 213, 238, 21, 85, 136, 12, 122, 41, 117, 33, 207, 177, 129, + 155, 248, 37, 162, 105, 168, 166, 60, 96, 205, 71, 165, 7, 114, 131, 4, 212, 185, 39, 11, + 69, 59, 43, 223, 254, 98, 54, 35, 56, 141, 20, 32, 154, 195, 55, 88, 38, 215, 87, 242, 233, + 13, 175, 23, 191, 100, 160, 256, 204, 18, 183, 190, 47, 178, 182, 137, 65, 104, 115, 184, + 243, 29, 252, 249, 90, 144, 179, 235, 119, 139, 171, 68, 6, 61, 149, 187, 145, 232, 217, + 193, 206, 124, 147, 81, 181, 84, 83, 30, 48, 231, 164, 211, 132, 57, 194, 2, 106, 221, 148, + 134, 163, 158, 150, 240, 127, 49, 27, 146, 28, 199, 10, 16, 77, 226, 156, 44, 19, 236, 172, + 121, 245, 135, 216, 140, 224, 50, 80, 128, 102, 9, 220, 95, 152, 89, 91, 197, 161, 52, 186, + 92, 250, 143, 126, 253, 45, 72, 218, 246, 188, 198, 214, 34, 3, 159, 203, 222, 201, 116, + 237, 225, 103, 62, 202, 169, 219, 42, 170, 15, 24, 244, 82, 234, 66, 157, 97, 1, + ], + [ + 1, 54, 89, 180, 211, 86, 18, 201, 60, 156, 200, 6, 67, 20, 52, 238, 2, 108, 178, 103, 165, + 172, 36, 145, 120, 55, 143, 12, 134, 40, 104, 219, 4, 216, 99, 206, 73, 87, 72, 33, 240, + 110, 29, 24, 11, 80, 208, 181, 8, 175, 198, 155, 146, 174, 144, 66, 223, 220, 58, 48, 22, + 160, 159, 105, 16, 93, 139, 53, 35, 91, 31, 132, 189, 183, 116, 96, 44, 63, 61, 210, 32, + 186, 21, 106, 70, 182, 62, 7, 121, 109, 232, 192, 88, 126, 122, 163, 64, 115, 42, 212, 140, + 107, 124, 14, 242, 218, 207, 127, 176, 252, 244, 69, 128, 230, 84, 167, 23, 214, 248, 28, + 227, 179, 157, 254, 95, 247, 231, 138, 256, 203, 168, 77, 46, 171, 239, 56, 197, 101, 57, + 251, 190, 237, 205, 19, 255, 149, 79, 154, 92, 85, 221, 112, 137, 202, 114, 245, 123, 217, + 153, 38, 253, 41, 158, 51, 184, 170, 185, 224, 17, 147, 228, 233, 246, 177, 49, 76, 249, 82, + 59, 102, 111, 83, 113, 191, 34, 37, 199, 209, 235, 97, 98, 152, 241, 164, 118, 204, 222, + 166, 226, 125, 68, 74, 141, 161, 213, 194, 196, 47, 225, 71, 236, 151, 187, 75, 195, 250, + 136, 148, 25, 65, 169, 131, 135, 94, 193, 142, 215, 45, 117, 150, 133, 243, 15, 39, 50, 130, + 81, 5, 13, 188, 129, 27, 173, 90, 234, 43, 9, 229, 30, 78, 100, 3, 162, 10, 26, 119, 1, + ], + [ + 1, 55, 198, 96, 140, 247, 221, 76, 68, 142, 100, 103, 11, 91, 122, 28, 255, 147, 118, 65, + 234, 20, 72, 105, 121, 230, 57, 51, 235, 75, 13, 201, 4, 220, 21, 127, 46, 217, 113, 47, 15, + 54, 143, 155, 44, 107, 231, 112, 249, 74, 215, 3, 165, 80, 31, 163, 227, 149, 228, 204, 169, + 43, 52, 33, 16, 109, 84, 251, 184, 97, 195, 188, 60, 216, 58, 106, 176, 171, 153, 191, 225, + 39, 89, 12, 146, 63, 124, 138, 137, 82, 141, 45, 162, 172, 208, 132, 64, 179, 79, 233, 222, + 131, 9, 238, 240, 93, 232, 167, 190, 170, 98, 250, 129, 156, 99, 48, 70, 252, 239, 38, 34, + 71, 50, 180, 134, 174, 61, 14, 256, 202, 59, 161, 117, 10, 36, 181, 189, 115, 157, 154, 246, + 166, 135, 229, 2, 110, 139, 192, 23, 237, 185, 152, 136, 27, 200, 206, 22, 182, 244, 56, + 253, 37, 236, 130, 211, 40, 144, 210, 242, 203, 114, 102, 213, 150, 26, 145, 8, 183, 42, + 254, 92, 177, 226, 94, 30, 108, 29, 53, 88, 214, 205, 224, 241, 148, 173, 6, 73, 160, 62, + 69, 197, 41, 199, 151, 81, 86, 104, 66, 32, 218, 168, 245, 111, 194, 133, 119, 120, 175, + 116, 212, 95, 85, 49, 125, 193, 78, 178, 24, 35, 126, 248, 19, 17, 164, 25, 90, 67, 87, 159, + 7, 128, 101, 158, 209, 187, 5, 18, 219, 223, 186, 207, 77, 123, 83, 196, 243, 1, + ], + [ + 1, 56, 52, 85, 134, 51, 29, 82, 223, 152, 31, 194, 70, 65, 42, 39, 128, 229, 231, 86, 190, + 103, 114, 216, 17, 181, 113, 160, 222, 96, 236, 109, 193, 14, 13, 214, 162, 77, 200, 149, + 120, 38, 72, 177, 146, 209, 139, 74, 32, 250, 122, 150, 176, 90, 157, 54, 197, 238, 221, 40, + 184, 24, 59, 220, 241, 132, 196, 182, 169, 212, 50, 230, 30, 138, 18, 237, 165, 245, 99, + 147, 8, 191, 159, 166, 44, 151, 232, 142, 242, 188, 248, 10, 46, 6, 79, 55, 253, 33, 49, + 174, 235, 53, 141, 186, 136, 163, 133, 252, 234, 254, 89, 101, 2, 112, 104, 170, 11, 102, + 58, 164, 189, 47, 62, 131, 140, 130, 84, 78, 256, 201, 205, 172, 123, 206, 228, 175, 34, + 105, 226, 63, 187, 192, 215, 218, 129, 28, 26, 171, 67, 154, 143, 41, 240, 76, 144, 97, 35, + 161, 21, 148, 64, 243, 244, 43, 95, 180, 57, 108, 137, 219, 185, 80, 111, 48, 118, 183, 225, + 7, 135, 107, 81, 167, 100, 203, 60, 19, 36, 217, 73, 233, 198, 37, 16, 125, 61, 75, 88, 45, + 207, 27, 227, 119, 239, 20, 92, 12, 158, 110, 249, 66, 98, 91, 213, 106, 25, 115, 15, 69, 9, + 247, 211, 251, 178, 202, 4, 224, 208, 83, 22, 204, 116, 71, 121, 94, 124, 5, 23, 3, 168, + 156, 255, 145, 153, 87, 246, 155, 199, 93, 68, 210, 195, 126, 117, 127, 173, 179, 1, + ], + [ + 1, 57, 165, 153, 240, 59, 22, 226, 32, 25, 140, 13, 227, 89, 190, 36, 253, 29, 111, 159, 68, + 21, 169, 124, 129, 157, 211, 205, 120, 158, 11, 113, 16, 141, 70, 135, 242, 173, 95, 18, + 255, 143, 184, 208, 34, 139, 213, 62, 193, 207, 234, 231, 60, 79, 134, 185, 8, 199, 35, 196, + 121, 215, 176, 9, 256, 200, 92, 104, 17, 198, 235, 31, 225, 232, 117, 244, 30, 168, 67, 221, + 4, 228, 146, 98, 189, 236, 88, 133, 128, 100, 46, 52, 137, 99, 246, 144, 241, 116, 187, 122, + 15, 84, 162, 239, 2, 114, 73, 49, 223, 118, 44, 195, 64, 50, 23, 26, 197, 178, 123, 72, 249, + 58, 222, 61, 136, 42, 81, 248, 1, 57, 165, 153, 240, 59, 22, 226, 32, 25, 140, 13, 227, 89, + 190, 36, 253, 29, 111, 159, 68, 21, 169, 124, 129, 157, 211, 205, 120, 158, 11, 113, 16, + 141, 70, 135, 242, 173, 95, 18, 255, 143, 184, 208, 34, 139, 213, 62, 193, 207, 234, 231, + 60, 79, 134, 185, 8, 199, 35, 196, 121, 215, 176, 9, 256, 200, 92, 104, 17, 198, 235, 31, + 225, 232, 117, 244, 30, 168, 67, 221, 4, 228, 146, 98, 189, 236, 88, 133, 128, 100, 46, 52, + 137, 99, 246, 144, 241, 116, 187, 122, 15, 84, 162, 239, 2, 114, 73, 49, 223, 118, 44, 195, + 64, 50, 23, 26, 197, 178, 123, 72, 249, 58, 222, 61, 136, 42, 81, 248, 1, + ], + [ + 1, 58, 23, 49, 15, 99, 88, 221, 225, 200, 35, 231, 34, 173, 11, 124, 253, 25, 165, 61, 197, + 118, 162, 144, 128, 228, 117, 104, 121, 79, 213, 18, 16, 157, 111, 13, 240, 42, 123, 195, 2, + 116, 46, 98, 30, 198, 176, 185, 193, 143, 70, 205, 68, 89, 22, 248, 249, 50, 73, 122, 137, + 236, 67, 31, 256, 199, 234, 208, 242, 158, 169, 36, 32, 57, 222, 26, 223, 84, 246, 133, 4, + 232, 92, 196, 60, 139, 95, 113, 129, 29, 140, 153, 136, 178, 44, 239, 241, 100, 146, 244, + 17, 215, 134, 62, 255, 141, 211, 159, 227, 59, 81, 72, 64, 114, 187, 52, 189, 168, 235, 9, + 8, 207, 184, 135, 120, 21, 190, 226, 1, 58, 23, 49, 15, 99, 88, 221, 225, 200, 35, 231, 34, + 173, 11, 124, 253, 25, 165, 61, 197, 118, 162, 144, 128, 228, 117, 104, 121, 79, 213, 18, + 16, 157, 111, 13, 240, 42, 123, 195, 2, 116, 46, 98, 30, 198, 176, 185, 193, 143, 70, 205, + 68, 89, 22, 248, 249, 50, 73, 122, 137, 236, 67, 31, 256, 199, 234, 208, 242, 158, 169, 36, + 32, 57, 222, 26, 223, 84, 246, 133, 4, 232, 92, 196, 60, 139, 95, 113, 129, 29, 140, 153, + 136, 178, 44, 239, 241, 100, 146, 244, 17, 215, 134, 62, 255, 141, 211, 159, 227, 59, 81, + 72, 64, 114, 187, 52, 189, 168, 235, 9, 8, 207, 184, 135, 120, 21, 190, 226, 1, + ], + [ + 1, 59, 140, 36, 68, 157, 11, 135, 255, 139, 234, 185, 121, 200, 235, 244, 4, 236, 46, 144, + 15, 114, 44, 26, 249, 42, 165, 226, 227, 29, 169, 205, 16, 173, 184, 62, 60, 199, 176, 104, + 225, 168, 146, 133, 137, 116, 162, 49, 64, 178, 222, 248, 240, 25, 190, 159, 129, 158, 70, + 18, 34, 207, 134, 196, 256, 198, 117, 221, 189, 100, 246, 122, 2, 118, 23, 72, 136, 57, 22, + 13, 253, 21, 211, 113, 242, 143, 213, 231, 8, 215, 92, 31, 30, 228, 88, 52, 241, 84, 73, + 195, 197, 58, 81, 153, 32, 89, 111, 124, 120, 141, 95, 208, 193, 79, 35, 9, 17, 232, 67, 98, + 128, 99, 187, 239, 223, 50, 123, 61, 1, 59, 140, 36, 68, 157, 11, 135, 255, 139, 234, 185, + 121, 200, 235, 244, 4, 236, 46, 144, 15, 114, 44, 26, 249, 42, 165, 226, 227, 29, 169, 205, + 16, 173, 184, 62, 60, 199, 176, 104, 225, 168, 146, 133, 137, 116, 162, 49, 64, 178, 222, + 248, 240, 25, 190, 159, 129, 158, 70, 18, 34, 207, 134, 196, 256, 198, 117, 221, 189, 100, + 246, 122, 2, 118, 23, 72, 136, 57, 22, 13, 253, 21, 211, 113, 242, 143, 213, 231, 8, 215, + 92, 31, 30, 228, 88, 52, 241, 84, 73, 195, 197, 58, 81, 153, 32, 89, 111, 124, 120, 141, 95, + 208, 193, 79, 35, 9, 17, 232, 67, 98, 128, 99, 187, 239, 223, 50, 123, 61, 1, + ], + [ + 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, + 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, + 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, + 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, + 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, + 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, + 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, + 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, + 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, + 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, + 64, 242, 128, 227, 256, 197, 255, 137, 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, + 30, 1, 60, 2, 120, 4, 240, 8, 223, 16, 189, 32, 121, 64, 242, 128, 227, 256, 197, 255, 137, + 253, 17, 249, 34, 241, 68, 225, 136, 193, 15, 129, 30, 1, + ], + [ + 1, 61, 123, 50, 223, 239, 187, 99, 128, 98, 67, 232, 17, 9, 35, 79, 193, 208, 95, 141, 120, + 124, 111, 89, 32, 153, 81, 58, 197, 195, 73, 84, 241, 52, 88, 228, 30, 31, 92, 215, 8, 231, + 213, 143, 242, 113, 211, 21, 253, 13, 22, 57, 136, 72, 23, 118, 2, 122, 246, 100, 189, 221, + 117, 198, 256, 196, 134, 207, 34, 18, 70, 158, 129, 159, 190, 25, 240, 248, 222, 178, 64, + 49, 162, 116, 137, 133, 146, 168, 225, 104, 176, 199, 60, 62, 184, 173, 16, 205, 169, 29, + 227, 226, 165, 42, 249, 26, 44, 114, 15, 144, 46, 236, 4, 244, 235, 200, 121, 185, 234, 139, + 255, 135, 11, 157, 68, 36, 140, 59, 1, 61, 123, 50, 223, 239, 187, 99, 128, 98, 67, 232, 17, + 9, 35, 79, 193, 208, 95, 141, 120, 124, 111, 89, 32, 153, 81, 58, 197, 195, 73, 84, 241, 52, + 88, 228, 30, 31, 92, 215, 8, 231, 213, 143, 242, 113, 211, 21, 253, 13, 22, 57, 136, 72, 23, + 118, 2, 122, 246, 100, 189, 221, 117, 198, 256, 196, 134, 207, 34, 18, 70, 158, 129, 159, + 190, 25, 240, 248, 222, 178, 64, 49, 162, 116, 137, 133, 146, 168, 225, 104, 176, 199, 60, + 62, 184, 173, 16, 205, 169, 29, 227, 226, 165, 42, 249, 26, 44, 114, 15, 144, 46, 236, 4, + 244, 235, 200, 121, 185, 234, 139, 255, 135, 11, 157, 68, 36, 140, 59, 1, + ], + [ + 1, 62, 246, 89, 121, 49, 211, 232, 249, 18, 88, 59, 60, 122, 111, 200, 64, 113, 67, 42, 34, + 52, 140, 199, 2, 124, 235, 178, 242, 98, 165, 207, 241, 36, 176, 118, 120, 244, 222, 143, + 128, 226, 134, 84, 68, 104, 23, 141, 4, 248, 213, 99, 227, 196, 73, 157, 225, 72, 95, 236, + 240, 231, 187, 29, 256, 195, 11, 168, 136, 208, 46, 25, 8, 239, 169, 198, 197, 135, 146, 57, + 193, 144, 190, 215, 223, 205, 117, 58, 255, 133, 22, 79, 15, 159, 92, 50, 16, 221, 81, 139, + 137, 13, 35, 114, 129, 31, 123, 173, 189, 153, 234, 116, 253, 9, 44, 158, 30, 61, 184, 100, + 32, 185, 162, 21, 17, 26, 70, 228, 1, 62, 246, 89, 121, 49, 211, 232, 249, 18, 88, 59, 60, + 122, 111, 200, 64, 113, 67, 42, 34, 52, 140, 199, 2, 124, 235, 178, 242, 98, 165, 207, 241, + 36, 176, 118, 120, 244, 222, 143, 128, 226, 134, 84, 68, 104, 23, 141, 4, 248, 213, 99, 227, + 196, 73, 157, 225, 72, 95, 236, 240, 231, 187, 29, 256, 195, 11, 168, 136, 208, 46, 25, 8, + 239, 169, 198, 197, 135, 146, 57, 193, 144, 190, 215, 223, 205, 117, 58, 255, 133, 22, 79, + 15, 159, 92, 50, 16, 221, 81, 139, 137, 13, 35, 114, 129, 31, 123, 173, 189, 153, 234, 116, + 253, 9, 44, 158, 30, 61, 184, 100, 32, 185, 162, 21, 17, 26, 70, 228, 1, + ], + [ + 1, 63, 114, 243, 146, 203, 196, 12, 242, 83, 89, 210, 123, 39, 144, 77, 225, 40, 207, 191, + 211, 186, 153, 130, 223, 171, 236, 219, 176, 37, 18, 106, 253, 5, 58, 56, 187, 216, 244, + 209, 60, 182, 158, 188, 22, 101, 195, 206, 128, 97, 200, 7, 184, 27, 159, 251, 136, 87, 84, + 152, 67, 109, 185, 90, 16, 237, 25, 33, 23, 164, 52, 192, 17, 43, 139, 19, 169, 110, 248, + 204, 2, 126, 228, 229, 35, 149, 135, 24, 227, 166, 178, 163, 246, 78, 31, 154, 193, 80, 157, + 125, 165, 115, 49, 3, 189, 85, 215, 181, 95, 74, 36, 212, 249, 10, 116, 112, 117, 175, 231, + 161, 120, 107, 59, 119, 44, 202, 133, 155, 256, 194, 143, 14, 111, 54, 61, 245, 15, 174, + 168, 47, 134, 218, 113, 180, 32, 217, 50, 66, 46, 71, 104, 127, 34, 86, 21, 38, 81, 220, + 239, 151, 4, 252, 199, 201, 70, 41, 13, 48, 197, 75, 99, 69, 235, 156, 62, 51, 129, 160, 57, + 250, 73, 230, 98, 6, 121, 170, 173, 105, 190, 148, 72, 167, 241, 20, 232, 224, 234, 93, 205, + 65, 240, 214, 118, 238, 88, 147, 9, 53, 255, 131, 29, 28, 222, 108, 122, 233, 30, 91, 79, + 94, 11, 179, 226, 103, 64, 177, 100, 132, 92, 142, 208, 254, 68, 172, 42, 76, 162, 183, 221, + 45, 8, 247, 141, 145, 140, 82, 26, 96, 137, 150, 198, 138, 213, 55, 124, 102, 1, + ], + [ + 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, + 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, + 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, + 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, + 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, + 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, + 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, + 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, + 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, + 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, + 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, + 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, 64, 241, 4, 256, 193, 16, 253, 1, + ], + [ + 1, 65, 113, 149, 176, 132, 99, 10, 136, 102, 205, 218, 35, 219, 100, 75, 249, 251, 124, 93, + 134, 229, 236, 177, 197, 212, 159, 55, 234, 47, 228, 171, 64, 48, 36, 27, 213, 224, 168, + 126, 223, 103, 13, 74, 184, 138, 232, 174, 2, 130, 226, 41, 95, 7, 198, 20, 15, 204, 153, + 179, 70, 181, 200, 150, 241, 245, 248, 186, 11, 201, 215, 97, 137, 167, 61, 110, 211, 94, + 199, 85, 128, 96, 72, 54, 169, 191, 79, 252, 189, 206, 26, 148, 111, 19, 207, 91, 4, 3, 195, + 82, 190, 14, 139, 40, 30, 151, 49, 101, 140, 105, 143, 43, 225, 233, 239, 115, 22, 145, 173, + 194, 17, 77, 122, 220, 165, 188, 141, 170, 256, 192, 144, 108, 81, 125, 158, 247, 121, 155, + 52, 39, 222, 38, 157, 182, 8, 6, 133, 164, 123, 28, 21, 80, 60, 45, 98, 202, 23, 210, 29, + 86, 193, 209, 221, 230, 44, 33, 89, 131, 34, 154, 244, 183, 73, 119, 25, 83, 255, 127, 31, + 216, 162, 250, 59, 237, 242, 53, 104, 78, 187, 76, 57, 107, 16, 12, 9, 71, 246, 56, 42, 160, + 120, 90, 196, 147, 46, 163, 58, 172, 129, 161, 185, 203, 88, 66, 178, 5, 68, 51, 231, 109, + 146, 238, 50, 166, 253, 254, 62, 175, 67, 243, 118, 217, 227, 106, 208, 156, 117, 152, 114, + 214, 32, 24, 18, 142, 235, 112, 84, 63, 240, 180, 135, 37, 92, 69, 116, 87, 1, + ], + [ + 1, 66, 244, 170, 169, 103, 116, 203, 34, 188, 72, 126, 92, 161, 89, 220, 128, 224, 135, 172, + 44, 77, 199, 27, 240, 163, 221, 194, 211, 48, 84, 147, 193, 145, 61, 171, 235, 90, 29, 115, + 137, 47, 18, 160, 23, 233, 215, 55, 32, 56, 98, 43, 11, 212, 114, 71, 60, 105, 248, 177, + 117, 12, 21, 101, 241, 229, 208, 107, 123, 151, 200, 93, 227, 76, 133, 40, 70, 251, 118, 78, + 8, 14, 153, 75, 67, 53, 157, 82, 15, 219, 62, 237, 222, 3, 198, 218, 253, 250, 52, 91, 95, + 102, 50, 216, 121, 19, 226, 10, 146, 127, 158, 148, 2, 132, 231, 83, 81, 206, 232, 149, 68, + 119, 144, 252, 184, 65, 178, 183, 256, 191, 13, 87, 88, 154, 141, 54, 223, 69, 185, 131, + 165, 96, 168, 37, 129, 33, 122, 85, 213, 180, 58, 230, 17, 94, 36, 63, 46, 209, 173, 110, + 64, 112, 196, 86, 22, 167, 228, 142, 120, 210, 239, 97, 234, 24, 42, 202, 225, 201, 159, + 214, 246, 45, 143, 186, 197, 152, 9, 80, 140, 245, 236, 156, 16, 28, 49, 150, 134, 106, 57, + 164, 30, 181, 124, 217, 187, 6, 139, 179, 249, 243, 104, 182, 190, 204, 100, 175, 242, 38, + 195, 20, 35, 254, 59, 39, 4, 7, 205, 166, 162, 155, 207, 41, 136, 238, 31, 247, 111, 130, + 99, 109, 255, 125, 26, 174, 176, 51, 25, 108, 189, 138, 113, 5, 73, 192, 79, 74, 1, + ], + [ + 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, 213, 136, 117, + 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, 235, 68, 187, + 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, 246, 34, 222, + 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, 17, 111, 241, + 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, 137, 184, 249, + 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, 197, 92, 253, + 246, 34, 222, 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, 46, 255, 123, + 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, 23, 256, 190, + 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, 140, 128, 95, + 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1, 67, 120, 73, 8, 22, 189, 70, 64, 176, 227, + 46, 255, 123, 17, 111, 241, 213, 136, 117, 129, 162, 60, 165, 4, 11, 223, 35, 32, 88, 242, + 23, 256, 190, 137, 184, 249, 235, 68, 187, 193, 81, 30, 211, 2, 134, 240, 146, 16, 44, 121, + 140, 128, 95, 197, 92, 253, 246, 34, 222, 225, 169, 15, 234, 1, + ], + [ + 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, + 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, + 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, + 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, + 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, + 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, + 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, + 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, + 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, + 241, 197, 32, 120, 193, 17, 128, 223, 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, + 64, 240, 129, 34, 256, 189, 2, 136, 253, 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, + 1, 68, 255, 121, 4, 15, 249, 227, 16, 60, 225, 137, 64, 240, 129, 34, 256, 189, 2, 136, 253, + 242, 8, 30, 241, 197, 32, 120, 193, 17, 128, 223, 1, + ], + [ + 1, 69, 135, 63, 235, 24, 114, 156, 227, 243, 62, 166, 146, 51, 178, 203, 129, 163, 196, 160, + 246, 12, 57, 78, 242, 250, 31, 83, 73, 154, 89, 230, 193, 210, 98, 80, 123, 6, 157, 39, 121, + 125, 144, 170, 165, 77, 173, 115, 225, 105, 49, 40, 190, 3, 207, 148, 189, 191, 72, 85, 211, + 167, 215, 186, 241, 181, 153, 20, 95, 130, 232, 74, 223, 224, 36, 171, 234, 212, 236, 93, + 249, 219, 205, 10, 176, 65, 116, 37, 240, 112, 18, 214, 117, 106, 118, 175, 253, 238, 231, + 5, 88, 161, 58, 147, 120, 56, 9, 107, 187, 53, 59, 216, 255, 119, 244, 131, 44, 209, 29, + 202, 60, 28, 133, 182, 222, 155, 158, 108, 256, 188, 122, 194, 22, 233, 143, 101, 30, 14, + 195, 91, 111, 206, 79, 54, 128, 94, 61, 97, 11, 245, 200, 179, 15, 7, 226, 174, 184, 103, + 168, 27, 64, 47, 159, 177, 134, 251, 100, 218, 136, 132, 113, 87, 92, 180, 84, 142, 32, 152, + 208, 217, 67, 254, 50, 109, 68, 66, 185, 172, 46, 90, 42, 71, 16, 76, 104, 237, 162, 127, + 25, 183, 34, 33, 221, 86, 23, 45, 21, 164, 8, 38, 52, 247, 81, 192, 141, 220, 17, 145, 239, + 43, 140, 151, 139, 82, 4, 19, 26, 252, 169, 96, 199, 110, 137, 201, 248, 150, 70, 204, 198, + 41, 2, 138, 13, 126, 213, 48, 228, 55, 197, 229, 124, 75, 35, 102, 99, 149, 1, + ], + [ + 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, + 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, + 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, + 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, 35, 137, 81, 16, + 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, 187, 240, 95, 225, + 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, 140, 34, 67, 64, + 111, 60, 88, 249, 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, 189, 123, 129, + 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, 136, 11, 256, + 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, 242, 235, 2, + 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1, 70, 17, 162, 32, 184, 30, 44, 253, 234, + 189, 123, 129, 35, 137, 81, 16, 92, 15, 22, 255, 117, 223, 190, 193, 146, 197, 169, 8, 46, + 136, 11, 256, 187, 240, 95, 225, 73, 227, 213, 4, 23, 68, 134, 128, 222, 120, 176, 241, 165, + 242, 235, 2, 140, 34, 67, 64, 111, 60, 88, 249, 211, 121, 246, 1, + ], + [ + 1, 71, 158, 167, 35, 172, 133, 191, 197, 109, 29, 3, 213, 217, 244, 105, 2, 142, 59, 77, 70, + 87, 9, 125, 137, 218, 58, 6, 169, 177, 231, 210, 4, 27, 118, 154, 140, 174, 18, 250, 17, + 179, 116, 12, 81, 97, 205, 163, 8, 54, 236, 51, 23, 91, 36, 243, 34, 101, 232, 24, 162, 194, + 153, 69, 16, 108, 215, 102, 46, 182, 72, 229, 68, 202, 207, 48, 67, 131, 49, 138, 32, 216, + 173, 204, 92, 107, 144, 201, 136, 147, 157, 96, 134, 5, 98, 19, 64, 175, 89, 151, 184, 214, + 31, 145, 15, 37, 57, 192, 11, 10, 196, 38, 128, 93, 178, 45, 111, 171, 62, 33, 30, 74, 114, + 127, 22, 20, 135, 76, 256, 186, 99, 90, 222, 85, 124, 66, 60, 148, 228, 254, 44, 40, 13, + 152, 255, 115, 198, 180, 187, 170, 248, 132, 120, 39, 199, 251, 88, 80, 26, 47, 253, 230, + 139, 103, 117, 83, 239, 7, 240, 78, 141, 245, 176, 160, 52, 94, 249, 203, 21, 206, 234, 166, + 221, 14, 223, 156, 25, 233, 95, 63, 104, 188, 241, 149, 42, 155, 211, 75, 185, 28, 189, 55, + 50, 209, 190, 126, 208, 119, 225, 41, 84, 53, 165, 150, 113, 56, 121, 110, 100, 161, 123, + 252, 159, 238, 193, 82, 168, 106, 73, 43, 226, 112, 242, 220, 200, 65, 246, 247, 61, 219, + 129, 164, 79, 212, 146, 86, 195, 224, 227, 183, 143, 130, 235, 237, 122, 181, 1, + ], + [ + 1, 72, 44, 84, 137, 98, 117, 200, 8, 62, 95, 158, 68, 13, 165, 58, 64, 239, 246, 236, 30, + 104, 35, 207, 255, 113, 169, 89, 240, 61, 23, 114, 241, 133, 67, 198, 121, 231, 184, 141, + 129, 36, 22, 42, 197, 49, 187, 100, 4, 31, 176, 79, 34, 135, 211, 29, 32, 248, 123, 118, 15, + 52, 146, 232, 256, 185, 213, 173, 120, 159, 140, 57, 249, 195, 162, 99, 189, 244, 92, 199, + 193, 18, 11, 21, 227, 153, 222, 50, 2, 144, 88, 168, 17, 196, 234, 143, 16, 124, 190, 59, + 136, 26, 73, 116, 128, 221, 235, 215, 60, 208, 70, 157, 253, 226, 81, 178, 223, 122, 46, + 228, 225, 9, 134, 139, 242, 205, 111, 25, 1, 72, 44, 84, 137, 98, 117, 200, 8, 62, 95, 158, + 68, 13, 165, 58, 64, 239, 246, 236, 30, 104, 35, 207, 255, 113, 169, 89, 240, 61, 23, 114, + 241, 133, 67, 198, 121, 231, 184, 141, 129, 36, 22, 42, 197, 49, 187, 100, 4, 31, 176, 79, + 34, 135, 211, 29, 32, 248, 123, 118, 15, 52, 146, 232, 256, 185, 213, 173, 120, 159, 140, + 57, 249, 195, 162, 99, 189, 244, 92, 199, 193, 18, 11, 21, 227, 153, 222, 50, 2, 144, 88, + 168, 17, 196, 234, 143, 16, 124, 190, 59, 136, 26, 73, 116, 128, 221, 235, 215, 60, 208, 70, + 157, 253, 226, 81, 178, 223, 122, 46, 228, 225, 9, 134, 139, 242, 205, 111, 25, 1, + ], + [ + 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, + 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, + 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, + 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, 187, 30, 134, + 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, 184, 68, 81, + 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, 137, 235, 193, + 211, 240, 44, 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, 242, 190, 249, + 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, 165, 223, 88, 256, + 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, 117, 60, 11, 32, 23, + 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1, 73, 189, 176, 255, 111, 136, 162, 4, 35, + 242, 190, 249, 187, 30, 134, 16, 140, 197, 246, 225, 234, 120, 22, 64, 46, 17, 213, 129, + 165, 223, 88, 256, 184, 68, 81, 2, 146, 121, 95, 253, 222, 15, 67, 8, 70, 227, 123, 241, + 117, 60, 11, 32, 23, 137, 235, 193, 211, 240, 44, 128, 92, 34, 169, 1, + ], + [ + 1, 74, 79, 192, 73, 5, 113, 138, 189, 108, 25, 51, 176, 174, 26, 125, 255, 109, 99, 130, + 111, 247, 31, 238, 136, 41, 207, 155, 162, 166, 205, 7, 4, 39, 59, 254, 35, 20, 195, 38, + 242, 175, 100, 204, 190, 182, 104, 243, 249, 179, 139, 6, 187, 217, 124, 181, 30, 164, 57, + 106, 134, 150, 49, 28, 16, 156, 236, 245, 140, 80, 9, 152, 197, 186, 143, 45, 246, 214, 159, + 201, 225, 202, 42, 24, 234, 97, 239, 210, 120, 142, 228, 167, 22, 86, 196, 112, 64, 110, + 173, 209, 46, 63, 36, 94, 17, 230, 58, 180, 213, 85, 122, 33, 129, 37, 168, 96, 165, 131, + 185, 69, 223, 54, 141, 154, 88, 87, 13, 191, 256, 183, 178, 65, 184, 252, 144, 119, 68, 149, + 232, 206, 81, 83, 231, 132, 2, 148, 158, 127, 146, 10, 226, 19, 121, 216, 50, 102, 95, 91, + 52, 250, 253, 218, 198, 3, 222, 237, 62, 219, 15, 82, 157, 53, 67, 75, 153, 14, 8, 78, 118, + 251, 70, 40, 133, 76, 227, 93, 200, 151, 123, 107, 208, 229, 241, 101, 21, 12, 117, 177, + 248, 105, 60, 71, 114, 212, 11, 43, 98, 56, 32, 55, 215, 233, 23, 160, 18, 47, 137, 115, 29, + 90, 235, 171, 61, 145, 193, 147, 84, 48, 211, 194, 221, 163, 240, 27, 199, 77, 44, 172, 135, + 224, 128, 220, 89, 161, 92, 126, 72, 188, 34, 203, 116, 103, 169, 170, 244, 66, 1, + ], + [ + 1, 75, 228, 138, 70, 110, 26, 151, 17, 247, 21, 33, 162, 71, 185, 254, 32, 87, 100, 47, 184, + 179, 61, 206, 30, 194, 158, 28, 44, 216, 9, 161, 253, 214, 116, 219, 234, 74, 153, 167, 189, + 40, 173, 125, 123, 230, 31, 12, 129, 166, 114, 69, 35, 55, 13, 204, 137, 252, 139, 145, 81, + 164, 221, 127, 16, 172, 50, 152, 92, 218, 159, 103, 15, 97, 79, 14, 22, 108, 133, 209, 255, + 107, 58, 238, 117, 37, 205, 212, 223, 20, 215, 191, 190, 115, 144, 6, 193, 83, 57, 163, 146, + 156, 135, 102, 197, 126, 198, 201, 169, 82, 239, 192, 8, 86, 25, 76, 46, 109, 208, 180, 136, + 177, 168, 7, 11, 54, 195, 233, 256, 182, 29, 119, 187, 147, 231, 106, 240, 10, 236, 224, 95, + 186, 72, 3, 225, 170, 157, 210, 73, 78, 196, 51, 227, 63, 99, 229, 213, 41, 248, 96, 4, 43, + 141, 38, 23, 183, 104, 90, 68, 217, 84, 132, 134, 27, 226, 245, 128, 91, 143, 188, 222, 202, + 244, 53, 120, 5, 118, 112, 176, 93, 36, 130, 241, 85, 207, 105, 165, 39, 98, 154, 242, 160, + 178, 243, 235, 149, 124, 48, 2, 150, 199, 19, 140, 220, 52, 45, 34, 237, 42, 66, 67, 142, + 113, 251, 64, 174, 200, 94, 111, 101, 122, 155, 60, 131, 59, 56, 88, 175, 18, 65, 249, 171, + 232, 181, 211, 148, 49, 77, 121, 80, 89, 250, 246, 203, 62, 24, 1, + ], + [ + 1, 76, 122, 20, 235, 127, 143, 74, 227, 33, 195, 171, 146, 45, 79, 93, 129, 38, 61, 10, 246, + 192, 200, 37, 242, 145, 226, 214, 73, 151, 168, 175, 193, 19, 159, 5, 123, 96, 100, 147, + 121, 201, 113, 107, 165, 204, 84, 216, 225, 138, 208, 131, 190, 48, 50, 202, 189, 229, 185, + 182, 211, 102, 42, 108, 241, 69, 104, 194, 95, 24, 25, 101, 223, 243, 221, 91, 234, 51, 21, + 54, 249, 163, 52, 97, 176, 12, 141, 179, 240, 250, 239, 174, 117, 154, 139, 27, 253, 210, + 26, 177, 88, 6, 199, 218, 120, 125, 248, 87, 187, 77, 198, 142, 255, 105, 13, 217, 44, 3, + 228, 109, 60, 191, 124, 172, 222, 167, 99, 71, 256, 181, 135, 237, 22, 130, 114, 183, 30, + 224, 62, 86, 111, 212, 178, 164, 128, 219, 196, 247, 11, 65, 57, 220, 15, 112, 31, 43, 184, + 106, 89, 82, 64, 238, 98, 252, 134, 161, 157, 110, 136, 56, 144, 150, 92, 53, 173, 41, 32, + 119, 49, 126, 67, 209, 207, 55, 68, 28, 72, 75, 46, 155, 215, 149, 16, 188, 153, 63, 162, + 233, 232, 156, 34, 14, 36, 166, 23, 206, 236, 203, 8, 94, 205, 160, 81, 245, 116, 78, 17, 7, + 18, 83, 140, 103, 118, 230, 4, 47, 231, 80, 169, 251, 58, 39, 137, 132, 9, 170, 70, 180, 59, + 115, 2, 152, 244, 40, 213, 254, 29, 148, 197, 66, 133, 85, 35, 90, 158, 186, 1, + ], + [ + 1, 77, 18, 101, 67, 19, 178, 85, 120, 245, 104, 41, 73, 224, 29, 177, 8, 102, 144, 37, 22, + 152, 139, 166, 189, 161, 61, 71, 70, 250, 232, 131, 64, 45, 124, 39, 176, 188, 84, 43, 227, + 3, 231, 54, 46, 201, 57, 20, 255, 103, 221, 55, 123, 219, 158, 87, 17, 24, 49, 175, 111, 66, + 199, 160, 241, 53, 226, 183, 213, 210, 236, 182, 136, 192, 135, 115, 117, 14, 50, 252, 129, + 167, 9, 179, 162, 138, 89, 171, 60, 251, 52, 149, 165, 112, 143, 217, 4, 51, 72, 147, 11, + 76, 198, 83, 223, 209, 159, 164, 35, 125, 116, 194, 32, 151, 62, 148, 88, 94, 42, 150, 242, + 130, 244, 27, 23, 229, 157, 10, 256, 180, 239, 156, 190, 238, 79, 172, 137, 12, 153, 216, + 184, 33, 228, 80, 249, 155, 113, 220, 235, 105, 118, 91, 68, 96, 196, 186, 187, 7, 25, 126, + 193, 212, 133, 218, 81, 69, 173, 214, 30, 254, 26, 203, 211, 56, 200, 237, 2, 154, 36, 202, + 134, 38, 99, 170, 240, 233, 208, 82, 146, 191, 58, 97, 16, 204, 31, 74, 44, 47, 21, 75, 121, + 65, 122, 142, 140, 243, 207, 5, 128, 90, 248, 78, 95, 119, 168, 86, 197, 6, 205, 108, 92, + 145, 114, 40, 253, 206, 185, 110, 246, 181, 59, 174, 34, 48, 98, 93, 222, 132, 141, 63, 225, + 106, 195, 109, 169, 163, 215, 107, 15, 127, 13, 230, 234, 28, 100, 247, 1, + ], + [ + 1, 78, 173, 130, 117, 131, 195, 47, 68, 164, 199, 102, 246, 170, 153, 112, 255, 101, 168, + 254, 23, 252, 124, 163, 121, 186, 116, 53, 22, 174, 208, 33, 4, 55, 178, 6, 211, 10, 9, 188, + 15, 142, 25, 151, 213, 166, 98, 191, 249, 147, 158, 245, 92, 237, 239, 138, 227, 230, 207, + 212, 88, 182, 61, 132, 16, 220, 198, 24, 73, 40, 36, 238, 60, 54, 100, 90, 81, 150, 135, + 250, 225, 74, 118, 209, 111, 177, 185, 38, 137, 149, 57, 77, 95, 214, 244, 14, 64, 109, 21, + 96, 35, 160, 144, 181, 240, 216, 143, 103, 67, 86, 26, 229, 129, 39, 215, 65, 187, 194, 226, + 152, 34, 82, 228, 51, 123, 85, 205, 56, 256, 179, 84, 127, 140, 126, 62, 210, 189, 93, 58, + 155, 11, 87, 104, 145, 2, 156, 89, 3, 234, 5, 133, 94, 136, 71, 141, 204, 235, 83, 49, 224, + 253, 202, 79, 251, 46, 247, 248, 69, 242, 115, 232, 106, 44, 91, 159, 66, 8, 110, 99, 12, + 165, 20, 18, 119, 30, 27, 50, 45, 169, 75, 196, 125, 241, 37, 59, 233, 184, 217, 221, 19, + 197, 203, 157, 167, 176, 107, 122, 7, 32, 183, 139, 48, 146, 80, 72, 219, 120, 108, 200, + 180, 162, 43, 13, 243, 193, 148, 236, 161, 222, 97, 113, 76, 17, 41, 114, 154, 190, 171, + 231, 28, 128, 218, 42, 192, 70, 63, 31, 105, 223, 175, 29, 206, 134, 172, 52, 201, 1, + ], + [ + 1, 79, 73, 113, 189, 25, 176, 26, 255, 99, 111, 31, 136, 207, 162, 205, 4, 59, 35, 195, 242, + 100, 190, 104, 249, 139, 187, 124, 30, 57, 134, 49, 16, 236, 140, 9, 197, 143, 246, 159, + 225, 42, 234, 239, 120, 228, 22, 196, 64, 173, 46, 36, 17, 58, 213, 122, 129, 168, 165, 185, + 223, 141, 88, 13, 256, 178, 184, 144, 68, 232, 81, 231, 2, 158, 146, 226, 121, 50, 95, 52, + 253, 198, 222, 62, 15, 157, 67, 153, 8, 118, 70, 133, 227, 200, 123, 208, 241, 21, 117, 248, + 60, 114, 11, 98, 32, 215, 23, 18, 137, 29, 235, 61, 193, 84, 211, 221, 240, 199, 44, 135, + 128, 89, 92, 72, 34, 116, 169, 244, 1, 79, 73, 113, 189, 25, 176, 26, 255, 99, 111, 31, 136, + 207, 162, 205, 4, 59, 35, 195, 242, 100, 190, 104, 249, 139, 187, 124, 30, 57, 134, 49, 16, + 236, 140, 9, 197, 143, 246, 159, 225, 42, 234, 239, 120, 228, 22, 196, 64, 173, 46, 36, 17, + 58, 213, 122, 129, 168, 165, 185, 223, 141, 88, 13, 256, 178, 184, 144, 68, 232, 81, 231, 2, + 158, 146, 226, 121, 50, 95, 52, 253, 198, 222, 62, 15, 157, 67, 153, 8, 118, 70, 133, 227, + 200, 123, 208, 241, 21, 117, 248, 60, 114, 11, 98, 32, 215, 23, 18, 137, 29, 235, 61, 193, + 84, 211, 221, 240, 199, 44, 135, 128, 89, 92, 72, 34, 116, 169, 244, 1, + ], + [ + 1, 80, 232, 56, 111, 142, 52, 48, 242, 85, 118, 188, 134, 183, 248, 51, 225, 10, 29, 7, 46, + 82, 135, 6, 223, 107, 79, 152, 81, 55, 31, 167, 253, 194, 100, 33, 70, 203, 49, 65, 60, 174, + 42, 19, 235, 39, 36, 53, 128, 217, 141, 229, 73, 186, 231, 233, 136, 86, 198, 163, 190, 37, + 133, 103, 16, 252, 114, 125, 234, 216, 61, 254, 17, 75, 89, 181, 88, 101, 113, 45, 2, 160, + 207, 112, 222, 27, 104, 96, 227, 170, 236, 119, 11, 109, 239, 102, 193, 20, 58, 14, 92, 164, + 13, 12, 189, 214, 158, 47, 162, 110, 62, 77, 249, 131, 200, 66, 140, 149, 98, 130, 120, 91, + 84, 38, 213, 78, 72, 106, 256, 177, 25, 201, 146, 115, 205, 209, 15, 172, 139, 69, 123, 74, + 9, 206, 32, 247, 228, 250, 211, 175, 122, 251, 34, 150, 178, 105, 176, 202, 226, 90, 4, 63, + 157, 224, 187, 54, 208, 192, 197, 83, 215, 238, 22, 218, 221, 204, 129, 40, 116, 28, 184, + 71, 26, 24, 121, 171, 59, 94, 67, 220, 124, 154, 241, 5, 143, 132, 23, 41, 196, 3, 240, 182, + 168, 76, 169, 156, 144, 212, 255, 97, 50, 145, 35, 230, 153, 161, 30, 87, 21, 138, 246, 148, + 18, 155, 64, 237, 199, 243, 165, 93, 244, 245, 68, 43, 99, 210, 95, 147, 195, 180, 8, 126, + 57, 191, 117, 108, 159, 127, 137, 166, 173, 219, 44, 179, 185, 151, 1, + ], + [ + 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, + 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, + 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, + 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, 2, 162, 15, 187, + 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, 256, 176, 121, 35, + 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, 129, 169, 68, 111, + 253, 190, 227, 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, 64, 44, 223, 73, + 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, 235, 17, 92, + 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, 11, 120, 211, + 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1, 81, 136, 222, 249, 123, 197, 23, + 64, 44, 223, 73, 2, 162, 15, 187, 241, 246, 137, 46, 128, 88, 189, 146, 4, 67, 30, 117, 225, + 235, 17, 92, 256, 176, 121, 35, 8, 134, 60, 234, 193, 213, 34, 184, 255, 95, 242, 70, 16, + 11, 120, 211, 129, 169, 68, 111, 253, 190, 227, 140, 32, 22, 240, 165, 1, + ], + [ + 1, 82, 42, 103, 222, 214, 72, 250, 197, 220, 50, 245, 44, 10, 49, 163, 2, 164, 84, 206, 187, + 171, 144, 243, 137, 183, 100, 233, 88, 20, 98, 69, 4, 71, 168, 155, 117, 85, 31, 229, 17, + 109, 200, 209, 176, 40, 196, 138, 8, 142, 79, 53, 234, 170, 62, 201, 34, 218, 143, 161, 95, + 80, 135, 19, 16, 27, 158, 106, 211, 83, 124, 145, 68, 179, 29, 65, 190, 160, 13, 38, 32, 54, + 59, 212, 165, 166, 248, 33, 136, 101, 58, 130, 123, 63, 26, 76, 64, 108, 118, 167, 73, 75, + 239, 66, 15, 202, 116, 3, 246, 126, 52, 152, 128, 216, 236, 77, 146, 150, 221, 132, 30, 147, + 232, 6, 235, 252, 104, 47, 256, 175, 215, 154, 35, 43, 185, 7, 60, 37, 207, 12, 213, 247, + 208, 94, 255, 93, 173, 51, 70, 86, 113, 14, 120, 74, 157, 24, 169, 237, 159, 188, 253, 186, + 89, 102, 140, 172, 226, 28, 240, 148, 57, 48, 81, 217, 61, 119, 249, 115, 178, 204, 23, 87, + 195, 56, 223, 39, 114, 96, 162, 177, 122, 238, 241, 230, 99, 151, 46, 174, 133, 112, 189, + 78, 228, 192, 67, 97, 244, 219, 225, 203, 198, 45, 92, 91, 9, 224, 121, 156, 199, 127, 134, + 194, 231, 181, 193, 149, 139, 90, 184, 182, 18, 191, 242, 55, 141, 254, 11, 131, 205, 105, + 129, 41, 21, 180, 111, 107, 36, 125, 227, 110, 25, 251, 22, 5, 153, 210, 1, + ], + [ + 1, 83, 207, 219, 187, 101, 159, 90, 17, 126, 178, 125, 95, 175, 133, 245, 32, 86, 199, 69, + 73, 148, 205, 53, 30, 177, 42, 145, 213, 203, 144, 130, 253, 182, 200, 152, 23, 110, 135, + 154, 189, 10, 59, 14, 134, 71, 239, 48, 129, 170, 232, 238, 222, 179, 208, 45, 137, 63, 89, + 191, 176, 216, 195, 251, 16, 43, 228, 163, 165, 74, 231, 155, 15, 217, 21, 201, 235, 230, + 72, 65, 255, 91, 100, 76, 140, 55, 196, 77, 223, 5, 158, 7, 67, 164, 248, 24, 193, 85, 116, + 119, 111, 218, 104, 151, 197, 160, 173, 224, 88, 108, 226, 254, 8, 150, 114, 210, 211, 37, + 244, 206, 136, 237, 139, 229, 246, 115, 36, 161, 256, 174, 50, 38, 70, 156, 98, 167, 240, + 131, 79, 132, 162, 82, 124, 12, 225, 171, 58, 188, 184, 109, 52, 204, 227, 80, 215, 112, 44, + 54, 113, 127, 4, 75, 57, 105, 234, 147, 122, 103, 68, 247, 198, 243, 123, 186, 18, 209, 128, + 87, 25, 19, 35, 78, 49, 212, 120, 194, 168, 66, 81, 41, 62, 6, 241, 214, 29, 94, 92, 183, + 26, 102, 242, 40, 236, 56, 22, 27, 185, 192, 2, 166, 157, 181, 117, 202, 61, 180, 34, 252, + 99, 250, 190, 93, 9, 233, 64, 172, 141, 138, 146, 39, 153, 106, 60, 97, 84, 33, 169, 149, + 31, 3, 249, 107, 143, 47, 46, 220, 13, 51, 121, 20, 118, 28, 11, 142, 221, 96, 1, + ], + [ + 1, 84, 117, 62, 68, 58, 246, 104, 255, 89, 23, 133, 121, 141, 22, 49, 4, 79, 211, 248, 15, + 232, 213, 159, 249, 99, 92, 18, 227, 50, 88, 196, 16, 59, 73, 221, 60, 157, 81, 122, 225, + 139, 111, 72, 137, 200, 95, 13, 64, 236, 35, 113, 240, 114, 67, 231, 129, 42, 187, 31, 34, + 29, 123, 52, 256, 173, 140, 195, 189, 199, 11, 153, 2, 168, 234, 124, 136, 116, 235, 208, + 253, 178, 46, 9, 242, 25, 44, 98, 8, 158, 165, 239, 30, 207, 169, 61, 241, 198, 184, 36, + 197, 100, 176, 135, 32, 118, 146, 185, 120, 57, 162, 244, 193, 21, 222, 144, 17, 143, 190, + 26, 128, 215, 70, 226, 223, 228, 134, 205, 1, 84, 117, 62, 68, 58, 246, 104, 255, 89, 23, + 133, 121, 141, 22, 49, 4, 79, 211, 248, 15, 232, 213, 159, 249, 99, 92, 18, 227, 50, 88, + 196, 16, 59, 73, 221, 60, 157, 81, 122, 225, 139, 111, 72, 137, 200, 95, 13, 64, 236, 35, + 113, 240, 114, 67, 231, 129, 42, 187, 31, 34, 29, 123, 52, 256, 173, 140, 195, 189, 199, 11, + 153, 2, 168, 234, 124, 136, 116, 235, 208, 253, 178, 46, 9, 242, 25, 44, 98, 8, 158, 165, + 239, 30, 207, 169, 61, 241, 198, 184, 36, 197, 100, 176, 135, 32, 118, 146, 185, 120, 57, + 162, 244, 193, 21, 222, 144, 17, 143, 190, 26, 128, 215, 70, 226, 223, 228, 134, 205, 1, + ], + [ + 1, 85, 29, 152, 70, 39, 231, 103, 17, 160, 236, 14, 162, 149, 72, 209, 32, 150, 157, 238, + 184, 220, 196, 212, 30, 237, 99, 191, 44, 142, 248, 6, 253, 174, 141, 163, 234, 101, 104, + 102, 189, 131, 84, 201, 123, 175, 226, 192, 129, 171, 143, 76, 35, 148, 244, 180, 137, 80, + 118, 7, 81, 203, 36, 233, 16, 75, 207, 119, 92, 110, 98, 106, 15, 247, 178, 224, 22, 71, + 124, 3, 255, 87, 199, 210, 117, 179, 52, 51, 223, 194, 42, 229, 190, 216, 113, 96, 193, 214, + 200, 38, 146, 74, 122, 90, 197, 40, 59, 132, 169, 230, 18, 245, 8, 166, 232, 188, 46, 55, + 49, 53, 136, 252, 89, 112, 11, 164, 62, 130, 256, 172, 228, 105, 187, 218, 26, 154, 240, 97, + 21, 243, 95, 108, 185, 48, 225, 107, 100, 19, 73, 37, 61, 45, 227, 20, 158, 66, 213, 115, 9, + 251, 4, 83, 116, 94, 23, 156, 153, 155, 68, 126, 173, 56, 134, 82, 31, 65, 128, 86, 114, + 181, 222, 109, 13, 77, 120, 177, 139, 250, 176, 54, 221, 24, 241, 182, 50, 138, 165, 147, + 159, 151, 242, 10, 79, 33, 235, 186, 133, 254, 2, 170, 58, 47, 140, 78, 205, 206, 34, 63, + 215, 28, 67, 41, 144, 161, 64, 43, 57, 219, 111, 183, 135, 167, 60, 217, 198, 125, 88, 27, + 239, 12, 249, 91, 25, 69, 211, 202, 208, 204, 121, 5, 168, 145, 246, 93, 195, 127, 1, + ], + [ + 1, 86, 200, 238, 165, 55, 104, 206, 240, 80, 198, 66, 22, 93, 31, 96, 32, 182, 232, 163, + 140, 218, 244, 167, 227, 247, 168, 56, 190, 149, 221, 245, 253, 170, 228, 76, 111, 37, 98, + 204, 68, 194, 236, 250, 169, 142, 133, 130, 129, 43, 100, 119, 211, 156, 52, 103, 120, 40, + 99, 33, 11, 175, 144, 48, 16, 91, 116, 210, 70, 109, 122, 212, 242, 252, 84, 28, 95, 203, + 239, 251, 255, 85, 114, 38, 184, 147, 49, 102, 34, 97, 118, 125, 213, 71, 195, 65, 193, 150, + 50, 188, 234, 78, 26, 180, 60, 20, 178, 145, 134, 216, 72, 24, 8, 174, 58, 105, 35, 183, 61, + 106, 121, 126, 42, 14, 176, 230, 248, 254, 256, 171, 57, 19, 92, 202, 153, 51, 17, 177, 59, + 191, 235, 164, 226, 161, 225, 75, 25, 94, 117, 39, 13, 90, 30, 10, 89, 201, 67, 108, 36, 12, + 4, 87, 29, 181, 146, 220, 159, 53, 189, 63, 21, 7, 88, 115, 124, 127, 128, 214, 157, 138, + 46, 101, 205, 154, 137, 217, 158, 224, 246, 82, 113, 209, 241, 166, 141, 47, 187, 148, 135, + 45, 15, 5, 173, 229, 162, 54, 18, 6, 2, 172, 143, 219, 73, 110, 208, 155, 223, 160, 139, + 132, 44, 186, 62, 192, 64, 107, 207, 69, 23, 179, 231, 77, 197, 237, 79, 112, 123, 41, 185, + 233, 249, 83, 199, 152, 222, 74, 196, 151, 136, 131, 215, 243, 81, 27, 9, 3, 1, + ], + [ + 1, 87, 116, 69, 92, 37, 135, 180, 240, 63, 84, 112, 235, 142, 18, 24, 32, 214, 114, 152, + 117, 156, 208, 106, 227, 217, 118, 243, 67, 175, 62, 254, 253, 166, 50, 238, 146, 109, 231, + 51, 68, 5, 178, 66, 88, 203, 185, 161, 129, 172, 58, 163, 46, 147, 196, 90, 120, 160, 42, + 56, 246, 71, 9, 12, 16, 107, 57, 76, 187, 78, 104, 53, 242, 237, 59, 250, 162, 216, 31, 127, + 255, 83, 25, 119, 73, 183, 244, 154, 34, 131, 89, 33, 44, 230, 221, 209, 193, 86, 29, 210, + 23, 202, 98, 45, 60, 80, 21, 28, 123, 164, 133, 6, 8, 182, 157, 38, 222, 39, 52, 155, 121, + 247, 158, 125, 81, 108, 144, 192, 256, 170, 141, 188, 165, 220, 122, 77, 17, 194, 173, 145, + 22, 115, 239, 233, 225, 43, 143, 105, 140, 101, 49, 151, 30, 40, 139, 14, 190, 82, 195, 3, + 4, 91, 207, 19, 111, 148, 26, 206, 189, 252, 79, 191, 169, 54, 72, 96, 128, 85, 199, 94, + 211, 110, 61, 167, 137, 97, 215, 201, 11, 186, 248, 245, 241, 150, 200, 181, 70, 179, 153, + 204, 15, 20, 198, 7, 95, 41, 226, 130, 2, 174, 232, 138, 184, 74, 13, 103, 223, 126, 168, + 224, 213, 27, 36, 48, 64, 171, 228, 47, 234, 55, 159, 212, 197, 177, 236, 229, 134, 93, 124, + 251, 249, 75, 100, 219, 35, 218, 205, 102, 136, 10, 99, 132, 176, 149, 113, 65, 1, + ], + [ + 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, + 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, + 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, + 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, 60, 140, 241, + 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, 223, 92, 129, + 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, 242, 222, 4, 95, + 136, 146, 255, 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, 137, 234, 32, 246, + 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, 68, 73, 256, 169, + 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, 30, 70, 249, 67, + 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1, 88, 34, 165, 128, 213, 240, 46, 193, 22, + 137, 234, 32, 246, 60, 140, 241, 134, 227, 187, 8, 190, 15, 35, 253, 162, 121, 111, 2, 176, + 68, 73, 256, 169, 223, 92, 129, 44, 17, 211, 64, 235, 120, 23, 225, 11, 197, 117, 16, 123, + 30, 70, 249, 67, 242, 222, 4, 95, 136, 146, 255, 81, 189, 184, 1, + ], + [ + 1, 89, 211, 18, 60, 200, 67, 52, 2, 178, 165, 36, 120, 143, 134, 104, 4, 99, 73, 72, 240, + 29, 11, 208, 8, 198, 146, 144, 223, 58, 22, 159, 16, 139, 35, 31, 189, 116, 44, 61, 32, 21, + 70, 62, 121, 232, 88, 122, 64, 42, 140, 124, 242, 207, 176, 244, 128, 84, 23, 248, 227, 157, + 95, 231, 256, 168, 46, 239, 197, 57, 190, 205, 255, 79, 92, 221, 137, 114, 123, 153, 253, + 158, 184, 185, 17, 228, 246, 49, 249, 59, 111, 113, 34, 199, 235, 98, 241, 118, 222, 226, + 68, 141, 213, 196, 225, 236, 187, 195, 136, 25, 169, 135, 193, 215, 117, 133, 15, 50, 81, + 13, 129, 173, 234, 9, 30, 100, 162, 26, 1, 89, 211, 18, 60, 200, 67, 52, 2, 178, 165, 36, + 120, 143, 134, 104, 4, 99, 73, 72, 240, 29, 11, 208, 8, 198, 146, 144, 223, 58, 22, 159, 16, + 139, 35, 31, 189, 116, 44, 61, 32, 21, 70, 62, 121, 232, 88, 122, 64, 42, 140, 124, 242, + 207, 176, 244, 128, 84, 23, 248, 227, 157, 95, 231, 256, 168, 46, 239, 197, 57, 190, 205, + 255, 79, 92, 221, 137, 114, 123, 153, 253, 158, 184, 185, 17, 228, 246, 49, 249, 59, 111, + 113, 34, 199, 235, 98, 241, 118, 222, 226, 68, 141, 213, 196, 225, 236, 187, 195, 136, 25, + 169, 135, 193, 215, 117, 133, 15, 50, 81, 13, 129, 173, 234, 9, 30, 100, 162, 26, 1, + ], + [ + 1, 90, 133, 148, 213, 152, 59, 170, 137, 251, 231, 230, 140, 7, 116, 160, 8, 206, 36, 156, + 162, 188, 215, 75, 68, 209, 49, 41, 92, 56, 157, 252, 64, 106, 31, 220, 11, 219, 178, 86, + 30, 130, 135, 71, 222, 191, 228, 217, 255, 77, 248, 218, 88, 210, 139, 174, 240, 12, 52, 54, + 234, 243, 25, 194, 241, 102, 185, 202, 190, 138, 84, 107, 121, 96, 159, 175, 73, 145, 200, + 10, 129, 45, 195, 74, 235, 76, 158, 85, 197, 254, 244, 115, 70, 132, 58, 80, 4, 103, 18, 78, + 81, 94, 236, 166, 34, 233, 153, 149, 46, 28, 207, 126, 32, 53, 144, 110, 134, 238, 89, 43, + 15, 65, 196, 164, 111, 224, 114, 237, 256, 167, 124, 109, 44, 105, 198, 87, 120, 6, 26, 27, + 117, 250, 141, 97, 249, 51, 221, 101, 95, 69, 42, 182, 189, 48, 208, 216, 165, 201, 100, 5, + 193, 151, 226, 37, 246, 38, 79, 171, 227, 127, 122, 186, 35, 66, 29, 40, 2, 180, 9, 39, 169, + 47, 118, 83, 17, 245, 205, 203, 23, 14, 232, 63, 16, 155, 72, 55, 67, 119, 173, 150, 136, + 161, 98, 82, 184, 112, 57, 247, 128, 212, 62, 183, 22, 181, 99, 172, 60, 3, 13, 142, 187, + 125, 199, 177, 253, 154, 239, 179, 176, 163, 21, 91, 223, 24, 104, 108, 211, 229, 50, 131, + 225, 204, 113, 147, 123, 19, 168, 214, 242, 192, 61, 93, 146, 33, 143, 20, 1, + ], + [ + 1, 91, 57, 47, 165, 109, 153, 45, 240, 252, 59, 229, 22, 203, 226, 6, 32, 85, 25, 219, 140, + 147, 13, 155, 227, 97, 89, 132, 190, 71, 36, 192, 253, 150, 29, 69, 111, 78, 159, 77, 68, + 20, 21, 112, 169, 216, 124, 233, 129, 174, 157, 152, 211, 183, 205, 151, 120, 126, 158, 243, + 11, 230, 113, 3, 16, 171, 141, 238, 70, 202, 135, 206, 242, 177, 173, 66, 95, 164, 18, 96, + 255, 75, 143, 163, 184, 39, 208, 167, 34, 10, 139, 56, 213, 108, 62, 245, 193, 87, 207, 76, + 234, 220, 231, 204, 60, 63, 79, 250, 134, 115, 185, 130, 8, 214, 199, 119, 35, 101, 196, + 103, 121, 217, 215, 33, 176, 82, 9, 48, 256, 166, 200, 210, 92, 148, 104, 212, 17, 5, 198, + 28, 235, 54, 31, 251, 225, 172, 232, 38, 117, 110, 244, 102, 30, 160, 168, 125, 67, 186, + 221, 65, 4, 107, 228, 188, 146, 179, 98, 180, 189, 237, 236, 145, 88, 41, 133, 24, 128, 83, + 100, 105, 46, 74, 52, 106, 137, 131, 99, 14, 246, 27, 144, 254, 241, 86, 116, 19, 187, 55, + 122, 51, 15, 80, 84, 191, 162, 93, 239, 161, 2, 182, 114, 94, 73, 218, 49, 90, 223, 247, + 118, 201, 44, 149, 195, 12, 64, 170, 50, 181, 23, 37, 26, 53, 197, 194, 178, 7, 123, 142, + 72, 127, 249, 43, 58, 138, 222, 156, 61, 154, 136, 40, 42, 224, 81, 175, 248, 209, 1, + ], + [ + 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, + 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, + 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, + 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, 46, 120, 246, 16, + 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, 165, 17, 22, 225, + 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, 184, 223, 213, 64, + 234, 197, 134, 249, 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, 146, 68, 88, 129, + 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, 222, 121, 81, 256, + 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, 70, 15, 95, 2, + 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1, 92, 240, 235, 32, 117, 227, 67, 253, + 146, 68, 88, 129, 46, 120, 246, 16, 187, 242, 162, 255, 73, 34, 44, 193, 23, 60, 123, 8, + 222, 121, 81, 256, 165, 17, 22, 225, 140, 30, 190, 4, 111, 189, 169, 128, 211, 137, 11, 241, + 70, 15, 95, 2, 184, 223, 213, 64, 234, 197, 134, 249, 35, 136, 176, 1, + ], + [ + 1, 93, 168, 204, 211, 91, 239, 125, 60, 183, 57, 161, 67, 63, 205, 47, 2, 186, 79, 151, 165, + 182, 221, 250, 120, 109, 114, 65, 134, 126, 153, 94, 4, 115, 158, 45, 73, 107, 185, 243, + 240, 218, 228, 130, 11, 252, 49, 188, 8, 230, 59, 90, 146, 214, 113, 229, 223, 179, 199, 3, + 22, 247, 98, 119, 16, 203, 118, 180, 35, 171, 226, 201, 189, 101, 141, 6, 44, 237, 196, 238, + 32, 149, 236, 103, 70, 85, 195, 145, 121, 202, 25, 12, 88, 217, 135, 219, 64, 41, 215, 206, + 140, 170, 133, 33, 242, 147, 50, 24, 176, 177, 13, 181, 128, 82, 173, 155, 23, 83, 9, 66, + 227, 37, 100, 48, 95, 97, 26, 105, 256, 164, 89, 53, 46, 166, 18, 132, 197, 74, 200, 96, + 190, 194, 52, 210, 255, 71, 178, 106, 92, 75, 36, 7, 137, 148, 143, 192, 123, 131, 104, 163, + 253, 142, 99, 212, 184, 150, 72, 14, 17, 39, 29, 127, 246, 5, 208, 69, 249, 27, 198, 167, + 111, 43, 144, 28, 34, 78, 58, 254, 235, 10, 159, 138, 241, 54, 139, 77, 222, 86, 31, 56, 68, + 156, 116, 251, 213, 20, 61, 19, 225, 108, 21, 154, 187, 172, 62, 112, 136, 55, 232, 245, + 169, 40, 122, 38, 193, 216, 42, 51, 117, 87, 124, 224, 15, 110, 207, 233, 81, 80, 244, 76, + 129, 175, 84, 102, 234, 174, 248, 191, 30, 220, 157, 209, 162, 160, 231, 152, 1, + ], + [ + 1, 94, 98, 217, 95, 192, 58, 55, 30, 250, 113, 85, 23, 106, 198, 108, 129, 47, 49, 237, 176, + 96, 29, 156, 15, 125, 185, 171, 140, 53, 99, 54, 193, 152, 153, 247, 88, 48, 143, 78, 136, + 191, 221, 214, 70, 155, 178, 27, 225, 76, 205, 252, 44, 24, 200, 39, 68, 224, 239, 107, 35, + 206, 89, 142, 241, 38, 231, 126, 22, 12, 100, 148, 34, 112, 248, 182, 146, 103, 173, 71, + 249, 19, 244, 63, 11, 6, 50, 74, 17, 56, 124, 91, 73, 180, 215, 164, 253, 138, 122, 160, + 134, 3, 25, 37, 137, 28, 62, 174, 165, 90, 236, 82, 255, 69, 61, 80, 67, 130, 141, 147, 197, + 14, 31, 87, 211, 45, 118, 41, 256, 163, 159, 40, 162, 65, 199, 202, 227, 7, 144, 172, 234, + 151, 59, 149, 128, 210, 208, 20, 81, 161, 228, 101, 242, 132, 72, 86, 117, 204, 158, 203, + 64, 105, 104, 10, 169, 209, 114, 179, 121, 66, 36, 43, 187, 102, 79, 230, 32, 181, 52, 5, + 213, 233, 57, 218, 189, 33, 18, 150, 222, 51, 168, 115, 16, 219, 26, 131, 235, 245, 157, + 109, 223, 145, 9, 75, 111, 154, 84, 186, 8, 238, 13, 194, 246, 251, 207, 183, 240, 201, 133, + 166, 184, 77, 42, 93, 4, 119, 135, 97, 123, 254, 232, 220, 120, 229, 195, 83, 92, 167, 21, + 175, 2, 188, 196, 177, 190, 127, 116, 110, 60, 243, 226, 170, 46, 212, 139, 216, 1, + ], + [ + 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, + 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, + 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, + 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, 225, 44, 68, 35, 241, + 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, 256, 162, 227, 234, + 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, 111, 8, 246, 240, + 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, 193, 88, 136, 70, + 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, 255, 67, 197, 211, + 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, 222, 16, 235, 223, + 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, 95, 30, 23, 129, 176, 15, 140, + 193, 88, 136, 70, 225, 44, 68, 35, 241, 22, 34, 146, 249, 11, 17, 73, 253, 134, 137, 165, + 255, 67, 197, 211, 256, 162, 227, 234, 128, 81, 242, 117, 64, 169, 121, 187, 32, 213, 189, + 222, 16, 235, 223, 111, 8, 246, 240, 184, 4, 123, 120, 92, 2, 190, 60, 46, 1, + ], + [ + 1, 96, 221, 142, 11, 28, 118, 20, 121, 51, 13, 220, 46, 47, 143, 107, 249, 3, 31, 149, 169, + 33, 84, 97, 60, 106, 153, 39, 146, 138, 141, 172, 64, 233, 9, 93, 190, 250, 99, 252, 34, + 180, 61, 202, 117, 181, 157, 166, 2, 192, 185, 27, 22, 56, 236, 40, 242, 102, 26, 183, 92, + 94, 29, 214, 241, 6, 62, 41, 81, 66, 168, 194, 120, 212, 49, 78, 35, 19, 25, 87, 128, 209, + 18, 186, 123, 243, 198, 247, 68, 103, 122, 147, 234, 105, 57, 75, 4, 127, 113, 54, 44, 112, + 215, 80, 227, 204, 52, 109, 184, 188, 58, 171, 225, 12, 124, 82, 162, 132, 79, 131, 240, + 167, 98, 156, 70, 38, 50, 174, 256, 161, 36, 115, 246, 229, 139, 237, 136, 206, 244, 37, + 211, 210, 114, 150, 8, 254, 226, 108, 88, 224, 173, 160, 197, 151, 104, 218, 111, 119, 116, + 85, 193, 24, 248, 164, 67, 7, 158, 5, 223, 77, 196, 55, 140, 76, 100, 91, 255, 65, 72, 230, + 235, 201, 21, 217, 15, 155, 231, 74, 165, 163, 228, 43, 16, 251, 195, 216, 176, 191, 89, 63, + 137, 45, 208, 179, 222, 238, 232, 170, 129, 48, 239, 71, 134, 14, 59, 10, 189, 154, 135, + 110, 23, 152, 200, 182, 253, 130, 144, 203, 213, 145, 42, 177, 30, 53, 205, 148, 73, 69, + 199, 86, 32, 245, 133, 175, 95, 125, 178, 126, 17, 90, 159, 101, 187, 219, 207, 83, 1, + ], + [ + 1, 97, 157, 66, 234, 82, 244, 24, 15, 170, 42, 219, 169, 202, 62, 103, 225, 237, 116, 201, + 222, 203, 159, 3, 34, 214, 198, 188, 246, 218, 72, 45, 253, 126, 143, 250, 92, 186, 52, 161, + 197, 91, 89, 152, 95, 220, 9, 102, 128, 80, 50, 224, 140, 216, 135, 245, 121, 172, 236, 19, + 44, 156, 226, 77, 16, 10, 199, 28, 146, 27, 49, 127, 240, 150, 158, 163, 134, 148, 221, 106, + 2, 194, 57, 132, 211, 164, 231, 48, 30, 83, 84, 181, 81, 147, 124, 206, 193, 217, 232, 145, + 187, 149, 61, 6, 68, 171, 139, 119, 235, 179, 144, 90, 249, 252, 29, 243, 184, 115, 104, 65, + 137, 182, 178, 47, 190, 183, 18, 204, 256, 160, 100, 191, 23, 175, 13, 233, 242, 87, 215, + 38, 88, 55, 195, 154, 32, 20, 141, 56, 35, 54, 98, 254, 223, 43, 59, 69, 11, 39, 185, 212, + 4, 131, 114, 7, 165, 71, 205, 96, 60, 166, 168, 105, 162, 37, 248, 155, 129, 177, 207, 33, + 117, 41, 122, 12, 136, 85, 21, 238, 213, 101, 31, 180, 241, 247, 58, 229, 111, 230, 208, + 130, 17, 107, 99, 94, 123, 109, 36, 151, 255, 63, 200, 125, 46, 93, 26, 209, 227, 174, 173, + 76, 176, 110, 133, 51, 64, 40, 25, 112, 70, 108, 196, 251, 189, 86, 118, 138, 22, 78, 113, + 167, 8, 5, 228, 14, 73, 142, 153, 192, 120, 75, 79, 210, 67, 74, 239, 53, 1, + ], + [ + 1, 98, 95, 58, 30, 113, 23, 198, 129, 49, 176, 29, 15, 185, 140, 99, 193, 153, 88, 143, 136, + 221, 70, 178, 225, 205, 44, 200, 68, 239, 35, 89, 241, 231, 22, 100, 34, 248, 146, 173, 249, + 244, 11, 50, 17, 124, 73, 215, 253, 122, 134, 25, 137, 62, 165, 236, 255, 61, 67, 141, 197, + 31, 211, 118, 256, 159, 162, 199, 227, 144, 234, 59, 128, 208, 81, 228, 242, 72, 117, 158, + 64, 104, 169, 114, 121, 36, 187, 79, 32, 52, 213, 57, 189, 18, 222, 168, 16, 26, 235, 157, + 223, 9, 111, 84, 8, 13, 246, 207, 240, 133, 184, 42, 4, 135, 123, 232, 120, 195, 92, 21, 2, + 196, 190, 116, 60, 226, 46, 139, 1, 98, 95, 58, 30, 113, 23, 198, 129, 49, 176, 29, 15, 185, + 140, 99, 193, 153, 88, 143, 136, 221, 70, 178, 225, 205, 44, 200, 68, 239, 35, 89, 241, 231, + 22, 100, 34, 248, 146, 173, 249, 244, 11, 50, 17, 124, 73, 215, 253, 122, 134, 25, 137, 62, + 165, 236, 255, 61, 67, 141, 197, 31, 211, 118, 256, 159, 162, 199, 227, 144, 234, 59, 128, + 208, 81, 228, 242, 72, 117, 158, 64, 104, 169, 114, 121, 36, 187, 79, 32, 52, 213, 57, 189, + 18, 222, 168, 16, 26, 235, 157, 223, 9, 111, 84, 8, 13, 246, 207, 240, 133, 184, 42, 4, 135, + 123, 232, 120, 195, 92, 21, 2, 196, 190, 116, 60, 226, 46, 139, 1, + ], + [ + 1, 99, 35, 124, 197, 228, 213, 13, 2, 198, 70, 248, 137, 199, 169, 26, 4, 139, 140, 239, 17, + 141, 81, 52, 8, 21, 23, 221, 34, 25, 162, 104, 16, 42, 46, 185, 68, 50, 67, 208, 32, 84, 92, + 113, 136, 100, 134, 159, 64, 168, 184, 226, 15, 200, 11, 61, 128, 79, 111, 195, 30, 143, 22, + 122, 256, 158, 222, 133, 60, 29, 44, 244, 255, 59, 187, 9, 120, 58, 88, 231, 253, 118, 117, + 18, 240, 116, 176, 205, 249, 236, 234, 36, 223, 232, 95, 153, 241, 215, 211, 72, 189, 207, + 190, 49, 225, 173, 165, 144, 121, 157, 123, 98, 193, 89, 73, 31, 242, 57, 246, 196, 129, + 178, 146, 62, 227, 114, 235, 135, 1, 99, 35, 124, 197, 228, 213, 13, 2, 198, 70, 248, 137, + 199, 169, 26, 4, 139, 140, 239, 17, 141, 81, 52, 8, 21, 23, 221, 34, 25, 162, 104, 16, 42, + 46, 185, 68, 50, 67, 208, 32, 84, 92, 113, 136, 100, 134, 159, 64, 168, 184, 226, 15, 200, + 11, 61, 128, 79, 111, 195, 30, 143, 22, 122, 256, 158, 222, 133, 60, 29, 44, 244, 255, 59, + 187, 9, 120, 58, 88, 231, 253, 118, 117, 18, 240, 116, 176, 205, 249, 236, 234, 36, 223, + 232, 95, 153, 241, 215, 211, 72, 189, 207, 190, 49, 225, 173, 165, 144, 121, 157, 123, 98, + 193, 89, 73, 31, 242, 57, 246, 196, 129, 178, 146, 62, 227, 114, 235, 135, 1, + ], + [ + 1, 100, 234, 13, 15, 215, 169, 195, 225, 141, 222, 98, 34, 59, 246, 185, 253, 114, 92, 205, + 197, 168, 95, 248, 128, 207, 140, 122, 121, 21, 44, 31, 16, 58, 146, 208, 240, 99, 134, 36, + 2, 200, 211, 26, 30, 173, 81, 133, 193, 25, 187, 196, 68, 118, 235, 113, 249, 228, 184, 153, + 137, 79, 190, 239, 256, 157, 23, 244, 242, 42, 88, 62, 32, 116, 35, 159, 223, 198, 11, 72, + 4, 143, 165, 52, 60, 89, 162, 9, 129, 50, 117, 135, 136, 236, 213, 226, 241, 199, 111, 49, + 17, 158, 123, 221, 255, 57, 46, 231, 227, 84, 176, 124, 64, 232, 70, 61, 189, 139, 22, 144, + 8, 29, 73, 104, 120, 178, 67, 18, 1, 100, 234, 13, 15, 215, 169, 195, 225, 141, 222, 98, 34, + 59, 246, 185, 253, 114, 92, 205, 197, 168, 95, 248, 128, 207, 140, 122, 121, 21, 44, 31, 16, + 58, 146, 208, 240, 99, 134, 36, 2, 200, 211, 26, 30, 173, 81, 133, 193, 25, 187, 196, 68, + 118, 235, 113, 249, 228, 184, 153, 137, 79, 190, 239, 256, 157, 23, 244, 242, 42, 88, 62, + 32, 116, 35, 159, 223, 198, 11, 72, 4, 143, 165, 52, 60, 89, 162, 9, 129, 50, 117, 135, 136, + 236, 213, 226, 241, 199, 111, 49, 17, 158, 123, 221, 255, 57, 46, 231, 227, 84, 176, 124, + 64, 232, 70, 61, 189, 139, 22, 144, 8, 29, 73, 104, 120, 178, 67, 18, 1, + ], + [ + 1, 101, 178, 245, 73, 177, 144, 152, 189, 71, 232, 45, 176, 43, 231, 201, 255, 55, 158, 24, + 111, 160, 226, 210, 136, 115, 50, 167, 162, 171, 52, 112, 4, 147, 198, 209, 35, 194, 62, 94, + 242, 27, 157, 180, 190, 172, 153, 33, 249, 220, 118, 96, 187, 126, 133, 69, 30, 203, 200, + 154, 134, 170, 208, 191, 16, 74, 21, 65, 140, 5, 248, 119, 197, 108, 114, 206, 246, 174, 98, + 132, 225, 109, 215, 127, 234, 247, 18, 19, 120, 41, 29, 102, 22, 166, 61, 250, 64, 39, 84, + 3, 46, 20, 221, 219, 17, 175, 199, 53, 213, 182, 135, 14, 129, 179, 89, 251, 165, 217, 72, + 76, 223, 164, 116, 151, 88, 150, 244, 229, 256, 156, 79, 12, 184, 80, 113, 105, 68, 186, 25, + 212, 81, 214, 26, 56, 2, 202, 99, 233, 146, 97, 31, 47, 121, 142, 207, 90, 95, 86, 205, 145, + 253, 110, 59, 48, 222, 63, 195, 163, 15, 230, 100, 77, 67, 85, 104, 224, 8, 37, 139, 161, + 70, 131, 124, 188, 227, 54, 57, 103, 123, 87, 49, 66, 241, 183, 236, 192, 117, 252, 9, 138, + 60, 149, 143, 51, 11, 83, 159, 125, 32, 148, 42, 130, 23, 10, 239, 238, 137, 216, 228, 155, + 235, 91, 196, 7, 193, 218, 173, 254, 211, 237, 36, 38, 240, 82, 58, 204, 44, 75, 122, 243, + 128, 78, 168, 6, 92, 40, 185, 181, 34, 93, 141, 106, 169, 107, 13, 28, 1, + ], + [ + 1, 102, 124, 55, 213, 138, 198, 150, 137, 96, 26, 82, 140, 145, 141, 247, 8, 45, 221, 183, + 162, 76, 42, 172, 68, 254, 208, 142, 92, 132, 100, 177, 64, 103, 226, 179, 11, 94, 79, 91, + 30, 233, 122, 108, 222, 28, 29, 131, 255, 53, 9, 147, 88, 238, 118, 214, 240, 65, 205, 93, + 234, 224, 232, 20, 241, 167, 72, 148, 190, 105, 173, 170, 121, 6, 98, 230, 73, 250, 57, 160, + 129, 51, 62, 156, 235, 69, 99, 75, 197, 48, 13, 41, 70, 201, 199, 252, 4, 151, 239, 220, 81, + 38, 21, 86, 34, 127, 104, 71, 46, 66, 50, 217, 32, 180, 113, 218, 134, 47, 168, 174, 15, + 245, 61, 54, 111, 14, 143, 194, 256, 155, 133, 202, 44, 119, 59, 107, 120, 161, 231, 175, + 117, 112, 116, 10, 249, 212, 36, 74, 95, 181, 215, 85, 189, 3, 49, 115, 165, 125, 157, 80, + 193, 154, 31, 78, 246, 163, 178, 166, 227, 24, 135, 149, 35, 229, 228, 126, 2, 204, 248, + 110, 169, 19, 139, 43, 17, 192, 52, 164, 23, 33, 25, 237, 16, 90, 185, 109, 67, 152, 84, 87, + 136, 251, 159, 27, 184, 7, 200, 97, 128, 206, 195, 101, 22, 188, 158, 182, 60, 209, 244, + 216, 187, 56, 58, 5, 253, 106, 18, 37, 176, 219, 236, 171, 223, 130, 153, 186, 211, 191, + 207, 40, 225, 77, 144, 39, 123, 210, 89, 83, 242, 12, 196, 203, 146, 243, 114, 63, 1, + ], + [ + 1, 103, 72, 220, 44, 163, 84, 171, 137, 233, 98, 71, 117, 229, 200, 40, 8, 53, 62, 218, 95, + 19, 158, 83, 68, 65, 13, 54, 165, 33, 58, 63, 64, 167, 239, 202, 246, 152, 236, 150, 30, 6, + 104, 175, 35, 7, 207, 247, 255, 51, 113, 74, 169, 188, 89, 172, 240, 48, 61, 115, 23, 56, + 114, 177, 241, 151, 133, 78, 67, 219, 198, 91, 121, 127, 231, 149, 184, 191, 141, 131, 129, + 180, 36, 110, 22, 210, 42, 214, 197, 245, 49, 164, 187, 243, 100, 20, 4, 155, 31, 109, 176, + 138, 79, 170, 34, 161, 135, 27, 211, 145, 29, 160, 32, 212, 248, 101, 123, 76, 118, 75, 15, + 3, 52, 216, 146, 132, 232, 252, 256, 154, 185, 37, 213, 94, 173, 86, 120, 24, 159, 186, 140, + 28, 57, 217, 249, 204, 195, 39, 162, 238, 99, 174, 189, 192, 244, 203, 92, 224, 199, 194, + 193, 90, 18, 55, 11, 105, 21, 107, 227, 251, 153, 82, 222, 250, 50, 10, 2, 206, 144, 183, + 88, 69, 168, 85, 17, 209, 196, 142, 234, 201, 143, 80, 16, 106, 124, 179, 190, 38, 59, 166, + 136, 130, 26, 108, 73, 66, 116, 126, 128, 77, 221, 147, 235, 47, 215, 43, 60, 12, 208, 93, + 70, 14, 157, 237, 253, 102, 226, 148, 81, 119, 178, 87, 223, 96, 122, 230, 46, 112, 228, 97, + 225, 45, 9, 156, 134, 181, 139, 182, 242, 254, 205, 41, 111, 125, 25, 5, 1, + ], + [ + 1, 104, 22, 232, 227, 221, 111, 236, 129, 52, 11, 116, 242, 239, 184, 118, 193, 26, 134, 58, + 121, 248, 92, 59, 225, 13, 67, 29, 189, 124, 46, 158, 241, 135, 162, 143, 223, 62, 23, 79, + 249, 196, 81, 200, 240, 31, 140, 168, 253, 98, 169, 100, 120, 144, 70, 84, 255, 49, 213, 50, + 60, 72, 35, 42, 256, 153, 235, 25, 30, 36, 146, 21, 128, 205, 246, 141, 15, 18, 73, 139, 64, + 231, 123, 199, 136, 9, 165, 198, 32, 244, 190, 228, 68, 133, 211, 99, 16, 122, 95, 114, 34, + 195, 234, 178, 8, 61, 176, 57, 17, 226, 117, 89, 4, 159, 88, 157, 137, 113, 187, 173, 2, + 208, 44, 207, 197, 185, 222, 215, 1, 104, 22, 232, 227, 221, 111, 236, 129, 52, 11, 116, + 242, 239, 184, 118, 193, 26, 134, 58, 121, 248, 92, 59, 225, 13, 67, 29, 189, 124, 46, 158, + 241, 135, 162, 143, 223, 62, 23, 79, 249, 196, 81, 200, 240, 31, 140, 168, 253, 98, 169, + 100, 120, 144, 70, 84, 255, 49, 213, 50, 60, 72, 35, 42, 256, 153, 235, 25, 30, 36, 146, 21, + 128, 205, 246, 141, 15, 18, 73, 139, 64, 231, 123, 199, 136, 9, 165, 198, 32, 244, 190, 228, + 68, 133, 211, 99, 16, 122, 95, 114, 34, 195, 234, 178, 8, 61, 176, 57, 17, 226, 117, 89, 4, + 159, 88, 157, 137, 113, 187, 173, 2, 208, 44, 207, 197, 185, 222, 215, 1, + ], + [ + 1, 105, 231, 97, 162, 48, 157, 37, 30, 66, 248, 83, 234, 155, 84, 82, 129, 181, 244, 177, + 81, 24, 207, 147, 15, 33, 124, 170, 117, 206, 42, 41, 193, 219, 122, 217, 169, 12, 232, 202, + 136, 145, 62, 85, 187, 103, 21, 149, 225, 238, 61, 237, 213, 6, 116, 101, 68, 201, 31, 171, + 222, 180, 139, 203, 241, 119, 159, 247, 235, 3, 58, 179, 34, 229, 144, 214, 111, 90, 198, + 230, 249, 188, 208, 252, 246, 130, 29, 218, 17, 243, 72, 107, 184, 45, 99, 115, 253, 94, + 104, 126, 123, 65, 143, 109, 137, 250, 36, 182, 92, 151, 178, 186, 255, 47, 52, 63, 190, + 161, 200, 183, 197, 125, 18, 91, 46, 204, 89, 93, 256, 152, 26, 160, 95, 209, 100, 220, 227, + 191, 9, 174, 23, 102, 173, 175, 128, 76, 13, 80, 176, 233, 50, 110, 242, 224, 133, 87, 140, + 51, 215, 216, 64, 38, 135, 40, 88, 245, 25, 55, 121, 112, 195, 172, 70, 154, 236, 108, 32, + 19, 196, 20, 44, 251, 141, 156, 189, 56, 226, 86, 35, 77, 118, 54, 16, 138, 98, 10, 22, 254, + 199, 78, 223, 28, 113, 43, 146, 167, 59, 27, 8, 69, 49, 5, 11, 127, 228, 39, 240, 14, 185, + 150, 73, 212, 158, 142, 4, 163, 153, 131, 134, 192, 114, 148, 120, 7, 221, 75, 165, 106, 79, + 71, 2, 210, 205, 194, 67, 96, 57, 74, 60, 132, 239, 166, 211, 53, 168, 164, 1, + ], + [ + 1, 106, 185, 78, 44, 38, 173, 91, 137, 130, 159, 149, 117, 66, 57, 131, 8, 77, 195, 110, 95, + 47, 99, 214, 68, 12, 244, 164, 165, 14, 199, 20, 64, 102, 18, 109, 246, 119, 21, 170, 30, + 96, 153, 27, 35, 112, 50, 160, 255, 45, 144, 101, 169, 181, 168, 75, 240, 254, 196, 216, 23, + 125, 143, 252, 241, 103, 124, 37, 67, 163, 59, 86, 121, 233, 26, 186, 184, 229, 116, 217, + 129, 53, 221, 39, 22, 19, 215, 174, 197, 65, 208, 203, 187, 33, 157, 194, 4, 167, 226, 55, + 176, 152, 178, 107, 34, 6, 122, 82, 211, 7, 228, 10, 32, 51, 9, 183, 123, 188, 139, 85, 15, + 48, 205, 142, 146, 56, 25, 80, 256, 151, 72, 179, 213, 219, 84, 166, 120, 127, 98, 108, 140, + 191, 200, 126, 249, 180, 62, 147, 162, 210, 158, 43, 189, 245, 13, 93, 92, 243, 58, 237, + 193, 155, 239, 148, 11, 138, 236, 87, 227, 161, 104, 230, 222, 145, 207, 97, 2, 212, 113, + 156, 88, 76, 89, 182, 17, 3, 61, 41, 234, 132, 114, 5, 16, 154, 133, 220, 190, 94, 198, 171, + 136, 24, 231, 71, 73, 28, 141, 40, 128, 204, 36, 218, 235, 238, 42, 83, 60, 192, 49, 54, 70, + 224, 100, 63, 253, 90, 31, 202, 81, 105, 79, 150, 223, 251, 135, 175, 46, 250, 29, 247, 225, + 206, 248, 74, 134, 69, 118, 172, 242, 209, 52, 115, 111, 201, 232, 177, 1, + ], + [ + 1, 107, 141, 181, 92, 78, 122, 204, 240, 237, 173, 7, 235, 216, 239, 130, 32, 83, 143, 138, + 117, 183, 49, 103, 227, 131, 139, 224, 67, 230, 195, 48, 253, 86, 207, 47, 146, 202, 26, + 212, 68, 80, 79, 229, 88, 164, 72, 251, 129, 182, 199, 219, 46, 39, 61, 102, 120, 247, 215, + 132, 246, 108, 248, 65, 16, 170, 200, 69, 187, 220, 153, 180, 242, 194, 198, 112, 162, 115, + 226, 24, 255, 43, 232, 152, 73, 101, 13, 106, 34, 40, 168, 243, 44, 82, 36, 254, 193, 91, + 228, 238, 23, 148, 159, 51, 60, 252, 236, 66, 123, 54, 124, 161, 8, 85, 100, 163, 222, 110, + 205, 90, 121, 97, 99, 56, 81, 186, 113, 12, 256, 150, 116, 76, 165, 179, 135, 53, 17, 20, + 84, 250, 22, 41, 18, 127, 225, 174, 114, 119, 140, 74, 208, 154, 30, 126, 118, 33, 190, 27, + 62, 209, 4, 171, 50, 210, 111, 55, 231, 45, 189, 177, 178, 28, 169, 93, 185, 6, 128, 75, 58, + 38, 211, 218, 196, 155, 137, 10, 42, 125, 11, 149, 9, 192, 241, 87, 57, 188, 70, 37, 104, + 77, 15, 63, 59, 145, 95, 142, 31, 233, 2, 214, 25, 105, 184, 156, 244, 151, 223, 217, 89, + 14, 213, 175, 221, 3, 64, 166, 29, 19, 234, 109, 98, 206, 197, 5, 21, 191, 134, 203, 133, + 96, 249, 172, 157, 94, 35, 147, 52, 167, 136, 160, 158, 201, 176, 71, 144, 245, 1, + ], + [ + 1, 108, 99, 155, 35, 182, 124, 28, 197, 202, 228, 209, 213, 131, 13, 119, 2, 216, 198, 53, + 70, 107, 248, 56, 137, 147, 199, 161, 169, 5, 26, 238, 4, 175, 139, 106, 140, 214, 239, 112, + 17, 37, 141, 65, 81, 10, 52, 219, 8, 93, 21, 212, 23, 171, 221, 224, 34, 74, 25, 130, 162, + 20, 104, 181, 16, 186, 42, 167, 46, 85, 185, 191, 68, 148, 50, 3, 67, 40, 208, 105, 32, 115, + 84, 77, 92, 170, 113, 125, 136, 39, 100, 6, 134, 80, 159, 210, 64, 230, 168, 154, 184, 83, + 226, 250, 15, 78, 200, 12, 11, 160, 61, 163, 128, 203, 79, 51, 111, 166, 195, 243, 30, 156, + 143, 24, 22, 63, 122, 69, 256, 149, 158, 102, 222, 75, 133, 229, 60, 55, 29, 48, 44, 126, + 244, 138, 255, 41, 59, 204, 187, 150, 9, 201, 120, 110, 58, 96, 88, 252, 231, 19, 253, 82, + 118, 151, 117, 43, 18, 145, 240, 220, 116, 192, 176, 247, 205, 38, 249, 164, 236, 45, 234, + 86, 36, 33, 223, 183, 232, 127, 95, 237, 153, 76, 241, 71, 215, 90, 211, 172, 72, 66, 189, + 109, 207, 254, 190, 217, 49, 152, 225, 142, 173, 180, 165, 87, 144, 132, 121, 218, 157, 251, + 123, 177, 98, 47, 193, 27, 89, 103, 73, 174, 31, 7, 242, 179, 57, 245, 246, 97, 196, 94, + 129, 54, 178, 206, 146, 91, 62, 14, 227, 101, 114, 233, 235, 194, 135, 188, 1, + ], + [ + 1, 109, 59, 6, 140, 97, 36, 69, 68, 216, 157, 151, 11, 171, 135, 66, 255, 39, 139, 245, 234, + 63, 185, 119, 121, 82, 200, 212, 235, 172, 244, 125, 4, 179, 236, 24, 46, 131, 144, 19, 15, + 93, 114, 90, 44, 170, 26, 7, 249, 156, 42, 209, 165, 252, 226, 219, 227, 71, 29, 77, 169, + 174, 205, 243, 16, 202, 173, 96, 184, 10, 62, 76, 60, 115, 199, 103, 176, 166, 104, 28, 225, + 110, 168, 65, 146, 237, 133, 105, 137, 27, 116, 51, 162, 182, 49, 201, 64, 37, 178, 127, + 222, 40, 248, 47, 240, 203, 25, 155, 190, 150, 159, 112, 129, 183, 158, 3, 70, 177, 18, 163, + 34, 108, 207, 204, 134, 214, 196, 33, 256, 148, 198, 251, 117, 160, 221, 188, 189, 41, 100, + 106, 246, 86, 122, 191, 2, 218, 118, 12, 23, 194, 72, 138, 136, 175, 57, 45, 22, 85, 13, + 132, 253, 78, 21, 233, 211, 126, 113, 238, 242, 164, 143, 167, 213, 87, 231, 250, 8, 101, + 215, 48, 92, 5, 31, 38, 30, 186, 228, 180, 88, 83, 52, 14, 241, 55, 84, 161, 73, 247, 195, + 181, 197, 142, 58, 154, 81, 91, 153, 229, 32, 147, 89, 192, 111, 20, 124, 152, 120, 230, + 141, 206, 95, 75, 208, 56, 193, 220, 79, 130, 35, 217, 9, 210, 17, 54, 232, 102, 67, 107, + 98, 145, 128, 74, 99, 254, 187, 80, 239, 94, 223, 149, 50, 53, 123, 43, 61, 224, 1, + ], + [ + 1, 110, 21, 254, 184, 194, 9, 219, 189, 230, 114, 204, 81, 172, 159, 14, 255, 37, 215, 6, + 146, 126, 239, 76, 136, 54, 29, 106, 95, 170, 196, 229, 4, 183, 84, 245, 222, 5, 36, 105, + 242, 149, 199, 45, 67, 174, 122, 56, 249, 148, 89, 24, 70, 247, 185, 47, 30, 216, 116, 167, + 123, 166, 13, 145, 16, 218, 79, 209, 117, 20, 144, 163, 197, 82, 25, 180, 11, 182, 231, 224, + 225, 78, 99, 96, 23, 217, 226, 188, 120, 93, 207, 154, 235, 150, 52, 66, 64, 101, 59, 65, + 211, 80, 62, 138, 17, 71, 100, 206, 44, 214, 153, 125, 129, 55, 139, 127, 92, 97, 133, 238, + 223, 115, 57, 102, 169, 86, 208, 7, 256, 147, 236, 3, 73, 63, 248, 38, 68, 27, 143, 53, 176, + 85, 98, 243, 2, 220, 42, 251, 111, 131, 18, 181, 121, 203, 228, 151, 162, 87, 61, 28, 253, + 74, 173, 12, 35, 252, 221, 152, 15, 108, 58, 212, 190, 83, 135, 201, 8, 109, 168, 233, 187, + 10, 72, 210, 227, 41, 141, 90, 134, 91, 244, 112, 241, 39, 178, 48, 140, 237, 113, 94, 60, + 175, 232, 77, 246, 75, 26, 33, 32, 179, 158, 161, 234, 40, 31, 69, 137, 164, 50, 103, 22, + 107, 205, 191, 193, 156, 198, 192, 46, 177, 195, 119, 240, 186, 157, 51, 213, 43, 104, 132, + 128, 202, 118, 130, 165, 160, 124, 19, 34, 142, 200, 155, 88, 171, 49, 250, 1, + ], + [ + 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, + 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, + 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, + 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, 136, 190, 16, + 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, 15, 123, 32, + 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, 30, 246, 64, + 165, 68, 95, 8, 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, 235, 128, 73, + 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, 213, 256, 146, + 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, 169, 255, 35, + 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1, 111, 242, 134, 225, 46, 223, 81, 253, 70, 60, + 235, 128, 73, 136, 190, 16, 234, 17, 88, 2, 222, 227, 11, 193, 92, 189, 162, 249, 140, 120, + 213, 256, 146, 15, 123, 32, 211, 34, 176, 4, 187, 197, 22, 129, 184, 121, 67, 241, 23, 240, + 169, 255, 35, 30, 246, 64, 165, 68, 95, 8, 117, 137, 44, 1, + ], + [ + 1, 112, 208, 166, 88, 90, 57, 216, 34, 210, 133, 247, 165, 233, 139, 148, 128, 201, 153, + 174, 213, 212, 100, 149, 240, 152, 62, 5, 46, 12, 59, 183, 193, 28, 52, 170, 22, 151, 207, + 54, 137, 181, 226, 126, 234, 251, 99, 37, 32, 243, 231, 172, 246, 53, 25, 230, 60, 38, 144, + 194, 140, 3, 79, 110, 241, 7, 13, 171, 134, 102, 116, 142, 227, 238, 185, 160, 187, 127, 89, + 202, 8, 125, 122, 43, 190, 206, 199, 186, 15, 138, 36, 177, 35, 65, 84, 156, 253, 66, 196, + 107, 162, 154, 29, 164, 121, 188, 239, 40, 111, 96, 215, 179, 2, 224, 159, 75, 176, 180, + 114, 175, 68, 163, 9, 237, 73, 209, 21, 39, 256, 145, 49, 91, 169, 167, 200, 41, 223, 47, + 124, 10, 92, 24, 118, 109, 129, 56, 104, 83, 44, 45, 157, 108, 17, 105, 195, 252, 211, 245, + 198, 74, 64, 229, 205, 87, 235, 106, 50, 203, 120, 76, 31, 131, 23, 6, 158, 220, 225, 14, + 26, 85, 11, 204, 232, 27, 197, 219, 113, 63, 117, 254, 178, 147, 16, 250, 244, 86, 123, 155, + 141, 115, 30, 19, 72, 97, 70, 130, 168, 55, 249, 132, 135, 214, 67, 51, 58, 71, 242, 119, + 221, 80, 222, 192, 173, 101, 4, 191, 61, 150, 95, 103, 228, 93, 136, 69, 18, 217, 146, 161, + 42, 78, 255, 33, 98, 182, 81, 77, 143, 82, 189, 94, 248, 20, 184, 48, 236, 218, 1, + ], + [ + 1, 113, 176, 99, 136, 205, 35, 100, 249, 124, 134, 236, 197, 159, 234, 228, 64, 36, 213, + 168, 223, 13, 184, 232, 2, 226, 95, 198, 15, 153, 70, 200, 241, 248, 11, 215, 137, 61, 211, + 199, 128, 72, 169, 79, 189, 26, 111, 207, 4, 195, 190, 139, 30, 49, 140, 143, 225, 239, 22, + 173, 17, 122, 165, 141, 256, 144, 81, 158, 121, 52, 222, 157, 8, 133, 123, 21, 60, 98, 23, + 29, 193, 221, 44, 89, 34, 244, 73, 25, 255, 31, 162, 59, 242, 104, 187, 57, 16, 9, 246, 42, + 120, 196, 46, 58, 129, 185, 88, 178, 68, 231, 146, 50, 253, 62, 67, 118, 227, 208, 117, 114, + 32, 18, 235, 84, 240, 135, 92, 116, 1, 113, 176, 99, 136, 205, 35, 100, 249, 124, 134, 236, + 197, 159, 234, 228, 64, 36, 213, 168, 223, 13, 184, 232, 2, 226, 95, 198, 15, 153, 70, 200, + 241, 248, 11, 215, 137, 61, 211, 199, 128, 72, 169, 79, 189, 26, 111, 207, 4, 195, 190, 139, + 30, 49, 140, 143, 225, 239, 22, 173, 17, 122, 165, 141, 256, 144, 81, 158, 121, 52, 222, + 157, 8, 133, 123, 21, 60, 98, 23, 29, 193, 221, 44, 89, 34, 244, 73, 25, 255, 31, 162, 59, + 242, 104, 187, 57, 16, 9, 246, 42, 120, 196, 46, 58, 129, 185, 88, 178, 68, 231, 146, 50, + 253, 62, 67, 118, 227, 208, 117, 114, 32, 18, 235, 84, 240, 135, 92, 116, 1, + ], + [ + 1, 114, 146, 196, 242, 89, 123, 144, 225, 207, 211, 153, 223, 236, 176, 18, 253, 58, 187, + 244, 60, 158, 22, 195, 128, 200, 184, 159, 136, 84, 67, 185, 16, 25, 23, 52, 17, 139, 169, + 248, 2, 228, 35, 135, 227, 178, 246, 31, 193, 157, 165, 49, 189, 215, 95, 36, 249, 116, 117, + 231, 120, 59, 44, 133, 256, 143, 111, 61, 15, 168, 134, 113, 32, 50, 46, 104, 34, 21, 81, + 239, 4, 199, 70, 13, 197, 99, 235, 62, 129, 57, 73, 98, 121, 173, 190, 72, 241, 232, 234, + 205, 240, 118, 88, 9, 255, 29, 222, 122, 30, 79, 11, 226, 64, 100, 92, 208, 68, 42, 162, + 221, 8, 141, 140, 26, 137, 198, 213, 124, 1, 114, 146, 196, 242, 89, 123, 144, 225, 207, + 211, 153, 223, 236, 176, 18, 253, 58, 187, 244, 60, 158, 22, 195, 128, 200, 184, 159, 136, + 84, 67, 185, 16, 25, 23, 52, 17, 139, 169, 248, 2, 228, 35, 135, 227, 178, 246, 31, 193, + 157, 165, 49, 189, 215, 95, 36, 249, 116, 117, 231, 120, 59, 44, 133, 256, 143, 111, 61, 15, + 168, 134, 113, 32, 50, 46, 104, 34, 21, 81, 239, 4, 199, 70, 13, 197, 99, 235, 62, 129, 57, + 73, 98, 121, 173, 190, 72, 241, 232, 234, 205, 240, 118, 88, 9, 255, 29, 222, 122, 30, 79, + 11, 226, 64, 100, 92, 208, 68, 42, 162, 221, 8, 141, 140, 26, 137, 198, 213, 124, 1, + ], + [ + 1, 115, 118, 206, 46, 150, 31, 224, 60, 218, 141, 24, 190, 5, 61, 76, 2, 230, 236, 155, 92, + 43, 62, 191, 120, 179, 25, 48, 123, 10, 122, 152, 4, 203, 215, 53, 184, 86, 124, 125, 240, + 101, 50, 96, 246, 20, 244, 47, 8, 149, 173, 106, 111, 172, 248, 250, 223, 202, 100, 192, + 235, 40, 231, 94, 16, 41, 89, 212, 222, 87, 239, 243, 189, 147, 200, 127, 213, 80, 205, 188, + 32, 82, 178, 167, 187, 174, 221, 229, 121, 37, 143, 254, 169, 160, 153, 119, 64, 164, 99, + 77, 117, 91, 185, 201, 242, 74, 29, 251, 81, 63, 49, 238, 128, 71, 198, 154, 234, 182, 113, + 145, 227, 148, 58, 245, 162, 126, 98, 219, 256, 142, 139, 51, 211, 107, 226, 33, 197, 39, + 116, 233, 67, 252, 196, 181, 255, 27, 21, 102, 165, 214, 195, 66, 137, 78, 232, 209, 134, + 247, 135, 105, 253, 54, 42, 204, 73, 171, 133, 132, 17, 156, 207, 161, 11, 237, 13, 210, + 249, 108, 84, 151, 146, 85, 9, 7, 34, 55, 157, 65, 22, 217, 26, 163, 241, 216, 168, 45, 35, + 170, 18, 14, 68, 110, 57, 130, 44, 177, 52, 69, 225, 175, 79, 90, 70, 83, 36, 28, 136, 220, + 114, 3, 88, 97, 104, 138, 193, 93, 158, 180, 140, 166, 72, 56, 15, 183, 228, 6, 176, 194, + 208, 19, 129, 186, 59, 103, 23, 75, 144, 112, 30, 109, 199, 12, 95, 131, 159, 38, 1, + ], + [ + 1, 116, 92, 135, 240, 84, 235, 18, 32, 114, 117, 208, 227, 118, 67, 62, 253, 50, 146, 231, + 68, 178, 88, 185, 129, 58, 46, 196, 120, 42, 246, 9, 16, 57, 187, 104, 242, 59, 162, 31, + 255, 25, 73, 244, 34, 89, 44, 221, 193, 29, 23, 98, 60, 21, 123, 133, 8, 157, 222, 52, 121, + 158, 81, 144, 256, 141, 165, 122, 17, 173, 22, 239, 225, 143, 140, 49, 30, 139, 190, 195, 4, + 207, 111, 26, 189, 79, 169, 72, 128, 199, 211, 61, 137, 215, 11, 248, 241, 200, 70, 153, 15, + 198, 95, 226, 2, 232, 184, 13, 223, 168, 213, 36, 64, 228, 234, 159, 197, 236, 134, 124, + 249, 100, 35, 205, 136, 99, 176, 113, 1, 116, 92, 135, 240, 84, 235, 18, 32, 114, 117, 208, + 227, 118, 67, 62, 253, 50, 146, 231, 68, 178, 88, 185, 129, 58, 46, 196, 120, 42, 246, 9, + 16, 57, 187, 104, 242, 59, 162, 31, 255, 25, 73, 244, 34, 89, 44, 221, 193, 29, 23, 98, 60, + 21, 123, 133, 8, 157, 222, 52, 121, 158, 81, 144, 256, 141, 165, 122, 17, 173, 22, 239, 225, + 143, 140, 49, 30, 139, 190, 195, 4, 207, 111, 26, 189, 79, 169, 72, 128, 199, 211, 61, 137, + 215, 11, 248, 241, 200, 70, 153, 15, 198, 95, 226, 2, 232, 184, 13, 223, 168, 213, 36, 64, + 228, 234, 159, 197, 236, 134, 124, 249, 100, 35, 205, 136, 99, 176, 113, 1, + ], + [ + 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, + 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, + 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, + 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, 92, 227, 88, 16, 73, + 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, 140, 189, 11, 2, 234, + 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, 146, 120, 162, 193, + 222, 17, 190, 128, 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, 211, 15, 213, 249, + 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, 187, 34, 123, 256, + 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, 184, 197, 176, 32, + 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1, 117, 68, 246, 255, 23, 121, 22, 4, + 211, 15, 213, 249, 92, 227, 88, 16, 73, 60, 81, 225, 111, 137, 95, 64, 35, 240, 67, 129, + 187, 34, 123, 256, 140, 189, 11, 2, 234, 136, 235, 253, 46, 242, 44, 8, 165, 30, 169, 241, + 184, 197, 176, 32, 146, 120, 162, 193, 222, 17, 190, 128, 70, 223, 134, 1, + ], + [ + 1, 118, 46, 31, 60, 141, 190, 61, 2, 236, 92, 62, 120, 25, 123, 122, 4, 215, 184, 124, 240, + 50, 246, 244, 8, 173, 111, 248, 223, 100, 235, 231, 16, 89, 222, 239, 189, 200, 213, 205, + 32, 178, 187, 221, 121, 143, 169, 153, 64, 99, 117, 185, 242, 29, 81, 49, 128, 198, 234, + 113, 227, 58, 162, 98, 256, 139, 211, 226, 197, 116, 67, 196, 255, 21, 165, 195, 137, 232, + 134, 135, 253, 42, 73, 133, 17, 207, 11, 13, 249, 84, 146, 9, 34, 157, 22, 26, 241, 168, 35, + 18, 68, 57, 44, 52, 225, 79, 70, 36, 136, 114, 88, 104, 193, 158, 140, 72, 15, 228, 176, + 208, 129, 59, 23, 144, 30, 199, 95, 159, 1, 118, 46, 31, 60, 141, 190, 61, 2, 236, 92, 62, + 120, 25, 123, 122, 4, 215, 184, 124, 240, 50, 246, 244, 8, 173, 111, 248, 223, 100, 235, + 231, 16, 89, 222, 239, 189, 200, 213, 205, 32, 178, 187, 221, 121, 143, 169, 153, 64, 99, + 117, 185, 242, 29, 81, 49, 128, 198, 234, 113, 227, 58, 162, 98, 256, 139, 211, 226, 197, + 116, 67, 196, 255, 21, 165, 195, 137, 232, 134, 135, 253, 42, 73, 133, 17, 207, 11, 13, 249, + 84, 146, 9, 34, 157, 22, 26, 241, 168, 35, 18, 68, 57, 44, 52, 225, 79, 70, 36, 136, 114, + 88, 104, 193, 158, 140, 72, 15, 228, 176, 208, 129, 59, 23, 144, 30, 199, 95, 159, 1, + ], + [ + 1, 119, 26, 10, 162, 3, 100, 78, 30, 229, 9, 43, 234, 90, 173, 27, 129, 188, 13, 5, 81, 130, + 50, 39, 15, 243, 133, 150, 117, 45, 215, 142, 193, 94, 135, 131, 169, 65, 25, 148, 136, 250, + 195, 75, 187, 151, 236, 71, 225, 47, 196, 194, 213, 161, 141, 74, 68, 125, 226, 166, 222, + 204, 118, 164, 241, 152, 98, 97, 235, 209, 199, 37, 34, 191, 113, 83, 111, 102, 59, 82, 249, + 76, 49, 177, 246, 233, 228, 147, 17, 224, 185, 170, 184, 51, 158, 41, 253, 38, 153, 217, + 123, 245, 114, 202, 137, 112, 221, 85, 92, 154, 79, 149, 255, 19, 205, 237, 190, 251, 57, + 101, 197, 56, 239, 171, 46, 77, 168, 203, 256, 138, 231, 247, 95, 254, 157, 179, 227, 28, + 248, 214, 23, 167, 84, 230, 128, 69, 244, 252, 176, 127, 207, 218, 242, 14, 124, 107, 140, + 212, 42, 115, 64, 163, 122, 126, 88, 192, 232, 109, 121, 7, 62, 182, 70, 106, 21, 186, 32, + 210, 61, 63, 44, 96, 116, 183, 189, 132, 31, 91, 35, 53, 139, 93, 16, 105, 159, 160, 22, 48, + 58, 220, 223, 66, 144, 174, 146, 155, 198, 175, 8, 181, 208, 80, 11, 24, 29, 110, 240, 33, + 72, 87, 73, 206, 99, 216, 4, 219, 104, 40, 134, 12, 143, 55, 120, 145, 36, 172, 165, 103, + 178, 108, 2, 238, 52, 20, 67, 6, 200, 156, 60, 201, 18, 86, 211, 180, 89, 54, 1, + ], + [ + 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, + 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, + 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, + 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, + 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, + 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, + 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, + 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, + 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, + 121, 128, 197, 253, 34, 225, 15, 1, 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, + 223, 32, 242, 256, 137, 249, 68, 193, 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, + 120, 8, 189, 64, 227, 255, 17, 241, 136, 129, 60, 4, 223, 32, 242, 256, 137, 249, 68, 193, + 30, 2, 240, 16, 121, 128, 197, 253, 34, 225, 15, 1, + ], + [ + 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, + 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, + 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, + 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, + 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, + 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, + 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, + 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, + 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, + 129, 189, 253, 30, 32, 17, 1, 121, 249, 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, + 240, 256, 136, 8, 197, 193, 223, 255, 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, 121, 249, + 60, 64, 34, 2, 242, 241, 120, 128, 68, 4, 227, 225, 240, 256, 136, 8, 197, 193, 223, 255, + 15, 16, 137, 129, 189, 253, 30, 32, 17, 1, + ], + [ + 1, 122, 235, 143, 227, 195, 146, 79, 129, 61, 246, 200, 242, 226, 73, 168, 193, 159, 123, + 100, 121, 113, 165, 84, 225, 208, 190, 50, 189, 185, 211, 42, 241, 104, 95, 25, 223, 221, + 234, 21, 249, 52, 176, 141, 240, 239, 117, 139, 253, 26, 88, 199, 120, 248, 187, 198, 255, + 13, 44, 228, 60, 124, 222, 99, 256, 135, 22, 114, 30, 62, 111, 178, 128, 196, 11, 57, 15, + 31, 184, 89, 64, 98, 134, 157, 136, 144, 92, 173, 32, 49, 67, 207, 68, 72, 46, 215, 16, 153, + 162, 232, 34, 36, 23, 236, 8, 205, 81, 116, 17, 18, 140, 118, 4, 231, 169, 58, 137, 9, 70, + 59, 2, 244, 213, 29, 197, 133, 35, 158, 1, 122, 235, 143, 227, 195, 146, 79, 129, 61, 246, + 200, 242, 226, 73, 168, 193, 159, 123, 100, 121, 113, 165, 84, 225, 208, 190, 50, 189, 185, + 211, 42, 241, 104, 95, 25, 223, 221, 234, 21, 249, 52, 176, 141, 240, 239, 117, 139, 253, + 26, 88, 199, 120, 248, 187, 198, 255, 13, 44, 228, 60, 124, 222, 99, 256, 135, 22, 114, 30, + 62, 111, 178, 128, 196, 11, 57, 15, 31, 184, 89, 64, 98, 134, 157, 136, 144, 92, 173, 32, + 49, 67, 207, 68, 72, 46, 215, 16, 153, 162, 232, 34, 36, 23, 236, 8, 205, 81, 116, 17, 18, + 140, 118, 4, 231, 169, 58, 137, 9, 70, 59, 2, 244, 213, 29, 197, 133, 35, 158, 1, + ], + [ + 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, + 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, + 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, + 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, 197, 73, 241, 88, + 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, 34, 70, 129, 190, + 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, 44, 15, 46, 4, 235, + 121, 234, 255, 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, 120, 111, 32, 81, + 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, 117, 256, 134, + 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, 227, 165, 249, + 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1, 123, 223, 187, 128, 67, 17, 35, 193, 95, + 120, 111, 32, 81, 197, 73, 241, 88, 30, 92, 8, 213, 242, 211, 253, 22, 136, 23, 2, 246, 189, + 117, 256, 134, 34, 70, 129, 190, 240, 222, 64, 162, 137, 146, 225, 176, 60, 184, 16, 169, + 227, 165, 249, 44, 15, 46, 4, 235, 121, 234, 255, 11, 68, 140, 1, + ], + [ + 1, 124, 213, 198, 137, 26, 140, 141, 8, 221, 162, 42, 68, 208, 92, 100, 64, 226, 11, 79, 30, + 122, 222, 29, 255, 9, 88, 118, 240, 205, 234, 232, 241, 72, 190, 173, 121, 98, 73, 57, 129, + 62, 235, 99, 197, 13, 70, 199, 4, 239, 81, 21, 34, 104, 46, 50, 32, 113, 134, 168, 15, 61, + 111, 143, 256, 133, 44, 59, 120, 231, 117, 116, 249, 36, 95, 215, 189, 49, 165, 157, 193, + 31, 246, 178, 227, 135, 35, 228, 2, 248, 169, 139, 17, 52, 23, 25, 16, 185, 67, 84, 136, + 159, 184, 200, 128, 195, 22, 158, 60, 244, 187, 58, 253, 18, 176, 236, 223, 153, 211, 207, + 225, 144, 123, 89, 242, 196, 146, 114, 1, 124, 213, 198, 137, 26, 140, 141, 8, 221, 162, 42, + 68, 208, 92, 100, 64, 226, 11, 79, 30, 122, 222, 29, 255, 9, 88, 118, 240, 205, 234, 232, + 241, 72, 190, 173, 121, 98, 73, 57, 129, 62, 235, 99, 197, 13, 70, 199, 4, 239, 81, 21, 34, + 104, 46, 50, 32, 113, 134, 168, 15, 61, 111, 143, 256, 133, 44, 59, 120, 231, 117, 116, 249, + 36, 95, 215, 189, 49, 165, 157, 193, 31, 246, 178, 227, 135, 35, 228, 2, 248, 169, 139, 17, + 52, 23, 25, 16, 185, 67, 84, 136, 159, 184, 200, 128, 195, 22, 158, 60, 244, 187, 58, 253, + 18, 176, 236, 223, 153, 211, 207, 225, 144, 123, 89, 242, 196, 146, 114, 1, + ], + [ + 1, 125, 205, 182, 134, 45, 228, 230, 223, 119, 226, 237, 70, 12, 215, 147, 128, 66, 26, 166, + 190, 106, 143, 142, 17, 69, 144, 10, 222, 251, 21, 55, 193, 224, 244, 174, 162, 204, 57, + 186, 120, 94, 185, 252, 146, 3, 118, 101, 32, 145, 135, 170, 176, 155, 100, 164, 197, 210, + 36, 131, 184, 127, 198, 78, 241, 56, 61, 172, 169, 51, 207, 175, 30, 152, 239, 63, 165, 65, + 158, 218, 8, 229, 98, 171, 44, 103, 25, 41, 242, 181, 9, 97, 46, 96, 178, 148, 253, 14, 208, + 43, 235, 77, 116, 108, 136, 38, 124, 80, 234, 209, 168, 183, 2, 250, 153, 107, 11, 90, 199, + 203, 189, 238, 195, 217, 140, 24, 173, 37, 256, 132, 52, 75, 123, 212, 29, 27, 34, 138, 31, + 20, 187, 245, 42, 110, 129, 191, 231, 91, 67, 151, 114, 115, 240, 188, 113, 247, 35, 6, 236, + 202, 64, 33, 13, 83, 95, 53, 200, 71, 137, 163, 72, 5, 111, 254, 139, 156, 225, 112, 122, + 87, 81, 102, 157, 93, 60, 47, 221, 126, 73, 130, 59, 179, 16, 201, 196, 85, 88, 206, 50, 82, + 227, 105, 18, 194, 92, 192, 99, 39, 249, 28, 159, 86, 213, 154, 232, 216, 15, 76, 248, 160, + 211, 161, 79, 109, 4, 243, 49, 214, 22, 180, 141, 149, 121, 219, 133, 177, 23, 48, 89, 74, + 255, 7, 104, 150, 246, 167, 58, 54, 68, 19, 62, 40, 117, 233, 84, 220, 1, + ], + [ + 1, 126, 199, 145, 23, 71, 208, 251, 15, 91, 158, 119, 88, 37, 36, 167, 225, 80, 57, 243, 35, + 41, 26, 192, 34, 172, 84, 47, 11, 101, 133, 53, 253, 10, 232, 191, 165, 230, 196, 24, 197, + 150, 139, 38, 162, 109, 113, 103, 128, 194, 29, 56, 117, 93, 153, 3, 121, 83, 178, 69, 213, + 110, 239, 45, 16, 217, 100, 7, 111, 108, 244, 161, 240, 171, 215, 105, 123, 78, 62, 102, 2, + 252, 141, 33, 46, 142, 159, 245, 30, 182, 59, 238, 176, 74, 72, 77, 193, 160, 114, 229, 70, + 82, 52, 127, 68, 87, 168, 94, 22, 202, 9, 106, 249, 20, 207, 125, 73, 203, 135, 48, 137, 43, + 21, 76, 67, 218, 226, 206, 256, 131, 58, 112, 234, 186, 49, 6, 242, 166, 99, 138, 169, 220, + 221, 90, 32, 177, 200, 14, 222, 216, 231, 65, 223, 85, 173, 210, 246, 156, 124, 204, 4, 247, + 25, 66, 92, 27, 61, 233, 60, 107, 118, 219, 95, 148, 144, 154, 129, 63, 228, 201, 140, 164, + 104, 254, 136, 174, 79, 188, 44, 147, 18, 212, 241, 40, 157, 250, 146, 149, 13, 96, 17, 86, + 42, 152, 134, 179, 195, 155, 255, 5, 116, 224, 211, 115, 98, 12, 227, 75, 198, 19, 81, 183, + 185, 180, 64, 97, 143, 28, 187, 175, 205, 130, 189, 170, 89, 163, 235, 55, 248, 151, 8, 237, + 50, 132, 184, 54, 122, 209, 120, 214, 236, 181, 190, 39, 31, 51, 1, + ], + [ + 1, 127, 195, 93, 246, 145, 168, 5, 121, 204, 208, 202, 211, 69, 25, 91, 249, 12, 239, 27, + 88, 125, 198, 217, 60, 167, 135, 183, 111, 219, 57, 43, 64, 161, 144, 41, 67, 28, 215, 63, + 34, 206, 205, 78, 140, 47, 58, 170, 2, 254, 133, 186, 235, 33, 79, 10, 242, 151, 159, 147, + 165, 138, 50, 182, 241, 24, 221, 54, 176, 250, 139, 177, 120, 77, 13, 109, 222, 181, 114, + 86, 128, 65, 31, 82, 134, 56, 173, 126, 68, 155, 153, 156, 23, 94, 116, 83, 4, 251, 9, 115, + 213, 66, 158, 20, 227, 45, 61, 37, 73, 19, 100, 107, 225, 48, 185, 108, 95, 243, 21, 97, + 240, 154, 26, 218, 187, 105, 228, 172, 256, 130, 62, 164, 11, 112, 89, 252, 136, 53, 49, 55, + 46, 188, 232, 166, 8, 245, 18, 230, 169, 132, 59, 40, 197, 90, 122, 74, 146, 38, 200, 214, + 193, 96, 113, 216, 190, 229, 42, 194, 223, 51, 52, 179, 117, 210, 199, 87, 255, 3, 124, 71, + 22, 224, 178, 247, 15, 106, 98, 110, 92, 119, 207, 75, 16, 233, 36, 203, 81, 7, 118, 80, + 137, 180, 244, 148, 35, 76, 143, 171, 129, 192, 226, 175, 123, 201, 84, 131, 189, 102, 104, + 101, 234, 163, 141, 174, 253, 6, 248, 142, 44, 191, 99, 237, 30, 212, 196, 220, 184, 238, + 157, 150, 32, 209, 72, 149, 162, 14, 236, 160, 17, 103, 231, 39, 70, 152, 29, 85, 1, + ], + [ + 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, + 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, + 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, + 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, + 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, + 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, + 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, + 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, + 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, + 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, + 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, + 2, 256, 129, 64, 225, 16, 249, 4, 255, 1, 128, 193, 32, 241, 8, 253, 2, 256, 129, 64, 225, + 16, 249, 4, 255, 1, + ], + [ + 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, + 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, + 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, + 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, + 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, + 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, + 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, + 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, + 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, + 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, + 193, 225, 241, 249, 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, + 253, 255, 256, 128, 64, 32, 16, 8, 4, 2, 1, 129, 193, 225, 241, 249, 253, 255, 256, 128, 64, + 32, 16, 8, 4, 2, 1, + ], + [ + 1, 130, 195, 164, 246, 112, 168, 252, 121, 53, 208, 55, 211, 188, 25, 166, 249, 245, 239, + 230, 88, 132, 198, 40, 60, 90, 135, 74, 111, 38, 57, 214, 64, 96, 144, 216, 67, 229, 215, + 194, 34, 51, 205, 179, 140, 210, 58, 87, 2, 3, 133, 71, 235, 224, 79, 247, 242, 106, 159, + 110, 165, 119, 50, 75, 241, 233, 221, 203, 176, 7, 139, 80, 120, 180, 13, 148, 222, 76, 114, + 171, 128, 192, 31, 175, 134, 201, 173, 131, 68, 102, 153, 101, 23, 163, 116, 174, 4, 6, 9, + 142, 213, 191, 158, 237, 227, 212, 61, 220, 73, 238, 100, 150, 225, 209, 185, 149, 95, 14, + 21, 160, 240, 103, 26, 39, 187, 152, 228, 85, 256, 127, 62, 93, 11, 145, 89, 5, 136, 204, + 49, 202, 46, 69, 232, 91, 8, 12, 18, 27, 169, 125, 59, 217, 197, 167, 122, 183, 146, 219, + 200, 43, 193, 161, 113, 41, 190, 28, 42, 63, 223, 206, 52, 78, 117, 47, 199, 170, 255, 254, + 124, 186, 22, 33, 178, 10, 15, 151, 98, 147, 92, 138, 207, 182, 16, 24, 36, 54, 81, 250, + 118, 177, 137, 77, 244, 109, 35, 181, 143, 86, 129, 65, 226, 82, 123, 56, 84, 126, 189, 155, + 104, 156, 234, 94, 141, 83, 253, 251, 248, 115, 44, 66, 99, 20, 30, 45, 196, 37, 184, 19, + 157, 107, 32, 48, 72, 108, 162, 243, 236, 97, 17, 154, 231, 218, 70, 105, 29, 172, 1, + ], + [ + 1, 131, 199, 112, 23, 186, 208, 6, 15, 166, 158, 138, 88, 220, 36, 90, 225, 177, 57, 14, 35, + 216, 26, 65, 34, 85, 84, 210, 11, 156, 133, 204, 253, 247, 232, 66, 165, 27, 196, 233, 197, + 107, 139, 219, 162, 148, 113, 154, 128, 63, 29, 201, 117, 164, 153, 254, 121, 174, 178, 188, + 213, 147, 239, 212, 16, 40, 100, 250, 111, 149, 244, 96, 240, 86, 215, 152, 123, 179, 62, + 155, 2, 5, 141, 224, 46, 115, 159, 12, 30, 75, 59, 19, 176, 183, 72, 180, 193, 97, 114, 28, + 70, 175, 52, 130, 68, 170, 168, 163, 22, 55, 9, 151, 249, 237, 207, 132, 73, 54, 135, 209, + 137, 214, 21, 181, 67, 39, 226, 51, 256, 126, 58, 145, 234, 71, 49, 251, 242, 91, 99, 119, + 169, 37, 221, 167, 32, 80, 200, 243, 222, 41, 231, 192, 223, 172, 173, 47, 246, 101, 124, + 53, 4, 10, 25, 191, 92, 230, 61, 24, 60, 150, 118, 38, 95, 109, 144, 103, 129, 194, 228, 56, + 140, 93, 104, 3, 136, 83, 79, 69, 44, 110, 18, 45, 241, 217, 157, 7, 146, 108, 13, 161, 17, + 171, 42, 105, 134, 78, 195, 102, 255, 252, 116, 33, 211, 142, 98, 245, 227, 182, 198, 238, + 81, 74, 185, 77, 64, 160, 143, 229, 187, 82, 205, 127, 189, 87, 89, 94, 235, 202, 248, 106, + 8, 20, 50, 125, 184, 203, 122, 48, 120, 43, 236, 76, 190, 218, 31, 206, 1, + ], + [ + 1, 132, 205, 75, 134, 212, 228, 27, 223, 138, 226, 20, 70, 245, 215, 110, 128, 191, 26, 91, + 190, 151, 143, 115, 17, 188, 144, 247, 222, 6, 21, 202, 193, 33, 244, 83, 162, 53, 57, 71, + 120, 163, 185, 5, 146, 254, 118, 156, 32, 112, 135, 87, 176, 102, 100, 93, 197, 47, 36, 126, + 184, 130, 198, 179, 241, 201, 61, 85, 169, 206, 207, 82, 30, 105, 239, 194, 165, 192, 158, + 39, 8, 28, 98, 86, 44, 154, 25, 216, 242, 76, 9, 160, 46, 161, 178, 109, 253, 243, 208, 214, + 235, 180, 116, 149, 136, 219, 124, 177, 234, 48, 168, 74, 2, 7, 153, 150, 11, 167, 199, 54, + 189, 19, 195, 40, 140, 233, 173, 220, 256, 125, 52, 182, 123, 45, 29, 230, 34, 119, 31, 237, + 187, 12, 42, 147, 129, 66, 231, 166, 67, 106, 114, 142, 240, 69, 113, 10, 35, 251, 236, 55, + 64, 224, 13, 174, 95, 204, 200, 186, 137, 94, 72, 252, 111, 3, 139, 101, 225, 145, 122, 170, + 81, 155, 157, 164, 60, 210, 221, 131, 73, 127, 59, 78, 16, 56, 196, 172, 88, 51, 50, 175, + 227, 152, 18, 63, 92, 65, 99, 218, 249, 229, 159, 171, 213, 103, 232, 41, 15, 181, 248, 97, + 211, 96, 79, 148, 4, 14, 49, 43, 22, 77, 141, 108, 121, 38, 133, 80, 23, 209, 89, 183, 255, + 250, 104, 107, 246, 90, 58, 203, 68, 238, 62, 217, 117, 24, 84, 37, 1, + ], + [ + 1, 133, 213, 59, 137, 231, 140, 116, 8, 36, 162, 215, 68, 49, 92, 157, 64, 31, 11, 178, 30, + 135, 222, 228, 255, 248, 88, 139, 240, 52, 234, 25, 241, 185, 190, 84, 121, 159, 73, 200, + 129, 195, 235, 158, 197, 244, 70, 58, 4, 18, 81, 236, 34, 153, 46, 207, 32, 144, 134, 89, + 15, 196, 111, 114, 256, 124, 44, 198, 120, 26, 117, 141, 249, 221, 95, 42, 189, 208, 165, + 100, 193, 226, 246, 79, 227, 122, 35, 29, 2, 9, 169, 118, 17, 205, 23, 232, 16, 72, 67, 173, + 136, 98, 184, 57, 128, 62, 22, 99, 60, 13, 187, 199, 253, 239, 176, 21, 223, 104, 211, 50, + 225, 113, 123, 168, 242, 61, 146, 143, 1, 133, 213, 59, 137, 231, 140, 116, 8, 36, 162, 215, + 68, 49, 92, 157, 64, 31, 11, 178, 30, 135, 222, 228, 255, 248, 88, 139, 240, 52, 234, 25, + 241, 185, 190, 84, 121, 159, 73, 200, 129, 195, 235, 158, 197, 244, 70, 58, 4, 18, 81, 236, + 34, 153, 46, 207, 32, 144, 134, 89, 15, 196, 111, 114, 256, 124, 44, 198, 120, 26, 117, 141, + 249, 221, 95, 42, 189, 208, 165, 100, 193, 226, 246, 79, 227, 122, 35, 29, 2, 9, 169, 118, + 17, 205, 23, 232, 16, 72, 67, 173, 136, 98, 184, 57, 128, 62, 22, 99, 60, 13, 187, 199, 253, + 239, 176, 21, 223, 104, 211, 50, 225, 113, 123, 168, 242, 61, 146, 143, 1, + ], + [ + 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, + 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, + 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, + 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, 146, 32, 176, 197, + 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, 140, 256, 123, 34, + 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, 92, 249, 213, 15, + 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, 222, 193, 162, 120, + 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, 136, 234, 2, 11, 189, + 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, 60, 73, 16, 88, 227, + 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, 134, 223, 70, 128, 190, 17, + 222, 193, 162, 120, 146, 32, 176, 197, 184, 241, 169, 30, 165, 8, 44, 242, 46, 253, 235, + 136, 234, 2, 11, 189, 140, 256, 123, 34, 187, 129, 67, 240, 35, 64, 95, 137, 111, 225, 81, + 60, 73, 16, 88, 227, 92, 249, 213, 15, 211, 4, 22, 121, 23, 255, 246, 68, 117, 1, + ], + [ + 1, 135, 235, 114, 227, 62, 146, 178, 129, 196, 246, 57, 242, 31, 73, 89, 193, 98, 123, 157, + 121, 144, 165, 173, 225, 49, 190, 207, 189, 72, 211, 215, 241, 153, 95, 232, 223, 36, 234, + 236, 249, 205, 176, 116, 240, 18, 117, 118, 253, 231, 88, 58, 120, 9, 187, 59, 255, 244, 44, + 29, 60, 133, 222, 158, 256, 122, 22, 143, 30, 195, 111, 79, 128, 61, 11, 200, 15, 226, 184, + 168, 64, 159, 134, 100, 136, 113, 92, 84, 32, 208, 67, 50, 68, 185, 46, 42, 16, 104, 162, + 25, 34, 221, 23, 21, 8, 52, 81, 141, 17, 239, 140, 139, 4, 26, 169, 199, 137, 248, 70, 198, + 2, 13, 213, 228, 197, 124, 35, 99, 1, 135, 235, 114, 227, 62, 146, 178, 129, 196, 246, 57, + 242, 31, 73, 89, 193, 98, 123, 157, 121, 144, 165, 173, 225, 49, 190, 207, 189, 72, 211, + 215, 241, 153, 95, 232, 223, 36, 234, 236, 249, 205, 176, 116, 240, 18, 117, 118, 253, 231, + 88, 58, 120, 9, 187, 59, 255, 244, 44, 29, 60, 133, 222, 158, 256, 122, 22, 143, 30, 195, + 111, 79, 128, 61, 11, 200, 15, 226, 184, 168, 64, 159, 134, 100, 136, 113, 92, 84, 32, 208, + 67, 50, 68, 185, 46, 42, 16, 104, 162, 25, 34, 221, 23, 21, 8, 52, 81, 141, 17, 239, 140, + 139, 4, 26, 169, 199, 137, 248, 70, 198, 2, 13, 213, 228, 197, 124, 35, 99, 1, + ], + [ + 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, + 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, + 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, + 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, + 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, + 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, + 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, + 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, + 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, + 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, + 189, 4, 30, 225, 17, 256, 121, 8, 60, 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, + 240, 1, 136, 249, 197, 64, 223, 2, 15, 241, 137, 128, 189, 4, 30, 225, 17, 256, 121, 8, 60, + 193, 34, 255, 242, 16, 120, 129, 68, 253, 227, 32, 240, 1, + ], + [ + 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, + 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, + 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, + 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, + 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, + 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, + 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, + 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, + 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, + 128, 60, 253, 223, 225, 242, 1, 137, 8, 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, + 15, 256, 120, 249, 189, 193, 227, 2, 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, 137, 8, + 68, 64, 30, 255, 240, 241, 121, 129, 197, 4, 34, 32, 15, 256, 120, 249, 189, 193, 227, 2, + 17, 16, 136, 128, 60, 253, 223, 225, 242, 1, + ], + [ + 1, 138, 26, 247, 162, 254, 100, 179, 30, 28, 9, 214, 234, 167, 173, 230, 129, 69, 13, 252, + 81, 127, 50, 218, 15, 14, 133, 107, 117, 212, 215, 115, 193, 163, 135, 126, 169, 192, 25, + 109, 136, 7, 195, 182, 187, 106, 236, 186, 225, 210, 196, 63, 213, 96, 141, 183, 68, 132, + 226, 91, 222, 53, 118, 93, 241, 105, 98, 160, 235, 48, 199, 220, 34, 66, 113, 174, 111, 155, + 59, 175, 249, 181, 49, 80, 246, 24, 228, 110, 17, 33, 185, 87, 184, 206, 158, 216, 253, 219, + 153, 40, 123, 12, 114, 55, 137, 145, 221, 172, 92, 103, 79, 108, 255, 238, 205, 20, 190, 6, + 57, 156, 197, 201, 239, 86, 46, 180, 168, 54, 256, 119, 231, 10, 95, 3, 157, 78, 227, 229, + 248, 43, 23, 90, 84, 27, 128, 188, 244, 5, 176, 130, 207, 39, 242, 243, 124, 150, 140, 45, + 42, 142, 64, 94, 122, 131, 88, 65, 232, 148, 121, 250, 62, 75, 70, 151, 21, 71, 32, 47, 61, + 194, 44, 161, 116, 74, 189, 125, 31, 166, 35, 204, 139, 164, 16, 152, 159, 97, 22, 209, 58, + 37, 223, 191, 144, 83, 146, 102, 198, 82, 8, 76, 208, 177, 11, 233, 29, 147, 240, 224, 72, + 170, 73, 51, 99, 41, 4, 38, 104, 217, 134, 245, 143, 202, 120, 112, 36, 85, 165, 154, 178, + 149, 2, 19, 52, 237, 67, 251, 200, 101, 60, 56, 18, 171, 211, 77, 89, 203, 1, + ], + [ + 1, 139, 46, 226, 60, 116, 190, 196, 2, 21, 92, 195, 120, 232, 123, 135, 4, 42, 184, 133, + 240, 207, 246, 13, 8, 84, 111, 9, 223, 157, 235, 26, 16, 168, 222, 18, 189, 57, 213, 52, 32, + 79, 187, 36, 121, 114, 169, 104, 64, 158, 117, 72, 242, 228, 81, 208, 128, 59, 234, 144, + 227, 199, 162, 159, 256, 118, 211, 31, 197, 141, 67, 61, 255, 236, 165, 62, 137, 25, 134, + 122, 253, 215, 73, 124, 17, 50, 11, 244, 249, 173, 146, 248, 34, 100, 22, 231, 241, 89, 35, + 239, 68, 200, 44, 205, 225, 178, 70, 221, 136, 143, 88, 153, 193, 99, 140, 185, 15, 29, 176, + 49, 129, 198, 23, 113, 30, 58, 95, 98, 1, 139, 46, 226, 60, 116, 190, 196, 2, 21, 92, 195, + 120, 232, 123, 135, 4, 42, 184, 133, 240, 207, 246, 13, 8, 84, 111, 9, 223, 157, 235, 26, + 16, 168, 222, 18, 189, 57, 213, 52, 32, 79, 187, 36, 121, 114, 169, 104, 64, 158, 117, 72, + 242, 228, 81, 208, 128, 59, 234, 144, 227, 199, 162, 159, 256, 118, 211, 31, 197, 141, 67, + 61, 255, 236, 165, 62, 137, 25, 134, 122, 253, 215, 73, 124, 17, 50, 11, 244, 249, 173, 146, + 248, 34, 100, 22, 231, 241, 89, 35, 239, 68, 200, 44, 205, 225, 178, 70, 221, 136, 143, 88, + 153, 193, 99, 140, 185, 15, 29, 176, 49, 129, 198, 23, 113, 30, 58, 95, 98, 1, + ], + [ + 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, 184, 60, 176, + 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, + 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, + 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, 227, 169, 16, + 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, 117, 189, 246, + 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, 120, 95, 193, + 35, 17, 67, 128, 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, 44, 249, 165, + 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, 34, 134, 256, + 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, 197, 81, 32, 111, + 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1, 140, 68, 11, 255, 234, 121, 235, 4, 46, 15, + 44, 249, 165, 227, 169, 16, 184, 60, 176, 225, 146, 137, 162, 64, 222, 240, 190, 129, 70, + 34, 134, 256, 117, 189, 246, 2, 23, 136, 22, 253, 211, 242, 213, 8, 92, 30, 88, 241, 73, + 197, 81, 32, 111, 120, 95, 193, 35, 17, 67, 128, 187, 223, 123, 1, + ], + [ + 1, 141, 92, 122, 240, 173, 235, 239, 32, 143, 117, 49, 227, 139, 67, 195, 253, 207, 146, 26, + 68, 79, 88, 72, 129, 199, 46, 61, 120, 215, 246, 248, 16, 200, 187, 153, 242, 198, 162, 226, + 255, 232, 73, 13, 34, 168, 44, 36, 193, 228, 23, 159, 60, 236, 123, 124, 8, 100, 222, 205, + 121, 99, 81, 113, 256, 116, 165, 135, 17, 84, 22, 18, 225, 114, 140, 208, 30, 118, 190, 62, + 4, 50, 111, 231, 189, 178, 169, 185, 128, 58, 211, 196, 137, 42, 11, 9, 241, 57, 70, 104, + 15, 59, 95, 31, 2, 25, 184, 244, 223, 89, 213, 221, 64, 29, 234, 98, 197, 21, 134, 133, 249, + 157, 35, 52, 136, 158, 176, 144, 1, 141, 92, 122, 240, 173, 235, 239, 32, 143, 117, 49, 227, + 139, 67, 195, 253, 207, 146, 26, 68, 79, 88, 72, 129, 199, 46, 61, 120, 215, 246, 248, 16, + 200, 187, 153, 242, 198, 162, 226, 255, 232, 73, 13, 34, 168, 44, 36, 193, 228, 23, 159, 60, + 236, 123, 124, 8, 100, 222, 205, 121, 99, 81, 113, 256, 116, 165, 135, 17, 84, 22, 18, 225, + 114, 140, 208, 30, 118, 190, 62, 4, 50, 111, 231, 189, 178, 169, 185, 128, 58, 211, 196, + 137, 42, 11, 9, 241, 57, 70, 104, 15, 59, 95, 31, 2, 25, 184, 244, 223, 89, 213, 221, 64, + 29, 234, 98, 197, 21, 134, 133, 249, 157, 35, 52, 136, 158, 176, 144, 1, + ], + [ + 1, 142, 118, 51, 46, 107, 31, 33, 60, 39, 141, 233, 190, 252, 61, 181, 2, 27, 236, 102, 92, + 214, 62, 66, 120, 78, 25, 209, 123, 247, 122, 105, 4, 54, 215, 204, 184, 171, 124, 132, 240, + 156, 50, 161, 246, 237, 244, 210, 8, 108, 173, 151, 111, 85, 248, 7, 223, 55, 100, 65, 235, + 217, 231, 163, 16, 216, 89, 45, 222, 170, 239, 14, 189, 110, 200, 130, 213, 177, 205, 69, + 32, 175, 178, 90, 187, 83, 221, 28, 121, 220, 143, 3, 169, 97, 153, 138, 64, 93, 99, 180, + 117, 166, 185, 56, 242, 183, 29, 6, 81, 194, 49, 19, 128, 186, 198, 103, 234, 75, 113, 112, + 227, 109, 58, 12, 162, 131, 98, 38, 256, 115, 139, 206, 211, 150, 226, 224, 197, 218, 116, + 24, 67, 5, 196, 76, 255, 230, 21, 155, 165, 43, 195, 191, 137, 179, 232, 48, 134, 10, 135, + 152, 253, 203, 42, 53, 73, 86, 133, 125, 17, 101, 207, 96, 11, 20, 13, 47, 249, 149, 84, + 106, 146, 172, 9, 250, 34, 202, 157, 192, 22, 40, 26, 94, 241, 41, 168, 212, 35, 87, 18, + 243, 68, 147, 57, 127, 44, 80, 52, 188, 225, 82, 79, 167, 70, 174, 36, 229, 136, 37, 114, + 254, 88, 160, 104, 119, 193, 164, 158, 77, 140, 91, 72, 201, 15, 74, 228, 251, 176, 63, 208, + 238, 129, 71, 59, 154, 23, 182, 144, 145, 30, 148, 199, 245, 95, 126, 159, 219, 1, + ], + [ + 1, 143, 146, 61, 242, 168, 123, 113, 225, 50, 211, 104, 223, 21, 176, 239, 253, 199, 187, + 13, 60, 99, 22, 62, 128, 57, 184, 98, 136, 173, 67, 72, 16, 232, 23, 205, 17, 118, 169, 9, + 2, 29, 35, 122, 227, 79, 246, 226, 193, 100, 165, 208, 189, 42, 95, 221, 249, 141, 117, 26, + 120, 198, 44, 124, 256, 114, 111, 196, 15, 89, 134, 144, 32, 207, 46, 153, 34, 236, 81, 18, + 4, 58, 70, 244, 197, 158, 235, 195, 129, 200, 73, 159, 121, 84, 190, 185, 241, 25, 234, 52, + 240, 139, 88, 248, 255, 228, 222, 135, 30, 178, 11, 31, 64, 157, 92, 49, 68, 215, 162, 36, + 8, 116, 140, 231, 137, 59, 213, 133, 1, 143, 146, 61, 242, 168, 123, 113, 225, 50, 211, 104, + 223, 21, 176, 239, 253, 199, 187, 13, 60, 99, 22, 62, 128, 57, 184, 98, 136, 173, 67, 72, + 16, 232, 23, 205, 17, 118, 169, 9, 2, 29, 35, 122, 227, 79, 246, 226, 193, 100, 165, 208, + 189, 42, 95, 221, 249, 141, 117, 26, 120, 198, 44, 124, 256, 114, 111, 196, 15, 89, 134, + 144, 32, 207, 46, 153, 34, 236, 81, 18, 4, 58, 70, 244, 197, 158, 235, 195, 129, 200, 73, + 159, 121, 84, 190, 185, 241, 25, 234, 52, 240, 139, 88, 248, 255, 228, 222, 135, 30, 178, + 11, 31, 64, 157, 92, 49, 68, 215, 162, 36, 8, 116, 140, 231, 137, 59, 213, 133, 1, + ], + [ + 1, 144, 176, 158, 136, 52, 35, 157, 249, 133, 134, 21, 197, 98, 234, 29, 64, 221, 213, 89, + 223, 244, 184, 25, 2, 31, 95, 59, 15, 104, 70, 57, 241, 9, 11, 42, 137, 196, 211, 58, 128, + 185, 169, 178, 189, 231, 111, 50, 4, 62, 190, 118, 30, 208, 140, 114, 225, 18, 22, 84, 17, + 135, 165, 116, 256, 113, 81, 99, 121, 205, 222, 100, 8, 124, 123, 236, 60, 159, 23, 228, + 193, 36, 44, 168, 34, 13, 73, 232, 255, 226, 162, 198, 242, 153, 187, 200, 16, 248, 246, + 215, 120, 61, 46, 199, 129, 72, 88, 79, 68, 26, 146, 207, 253, 195, 67, 139, 227, 49, 117, + 143, 32, 239, 235, 173, 240, 122, 92, 141, 1, 144, 176, 158, 136, 52, 35, 157, 249, 133, + 134, 21, 197, 98, 234, 29, 64, 221, 213, 89, 223, 244, 184, 25, 2, 31, 95, 59, 15, 104, 70, + 57, 241, 9, 11, 42, 137, 196, 211, 58, 128, 185, 169, 178, 189, 231, 111, 50, 4, 62, 190, + 118, 30, 208, 140, 114, 225, 18, 22, 84, 17, 135, 165, 116, 256, 113, 81, 99, 121, 205, 222, + 100, 8, 124, 123, 236, 60, 159, 23, 228, 193, 36, 44, 168, 34, 13, 73, 232, 255, 226, 162, + 198, 242, 153, 187, 200, 16, 248, 246, 215, 120, 61, 46, 199, 129, 72, 88, 79, 68, 26, 146, + 207, 253, 195, 67, 139, 227, 49, 117, 143, 32, 239, 235, 173, 240, 122, 92, 141, 1, + ], + [ + 1, 145, 208, 91, 88, 167, 57, 41, 34, 47, 133, 10, 165, 24, 139, 109, 128, 56, 153, 83, 213, + 45, 100, 108, 240, 105, 62, 252, 46, 245, 59, 74, 193, 229, 52, 87, 22, 106, 207, 203, 137, + 76, 226, 131, 234, 6, 99, 220, 32, 14, 231, 85, 246, 204, 25, 27, 60, 219, 144, 63, 140, + 254, 79, 147, 241, 250, 13, 86, 134, 155, 116, 115, 227, 19, 185, 97, 187, 130, 89, 55, 8, + 132, 122, 214, 190, 51, 199, 71, 15, 119, 36, 80, 35, 192, 84, 101, 253, 191, 196, 150, 162, + 103, 29, 93, 121, 69, 239, 217, 111, 161, 215, 78, 2, 33, 159, 182, 176, 77, 114, 82, 68, + 94, 9, 20, 73, 48, 21, 218, 256, 112, 49, 166, 169, 90, 200, 216, 223, 210, 124, 247, 92, + 233, 118, 148, 129, 201, 104, 174, 44, 212, 157, 149, 17, 152, 195, 5, 211, 12, 198, 183, + 64, 28, 205, 170, 235, 151, 50, 54, 120, 181, 31, 126, 23, 251, 158, 37, 225, 243, 26, 172, + 11, 53, 232, 230, 197, 38, 113, 194, 117, 3, 178, 110, 16, 7, 244, 171, 123, 102, 141, 142, + 30, 238, 72, 160, 70, 127, 168, 202, 249, 125, 135, 43, 67, 206, 58, 186, 242, 138, 221, + 177, 222, 65, 173, 156, 4, 66, 61, 107, 95, 154, 228, 164, 136, 188, 18, 40, 146, 96, 42, + 179, 255, 224, 98, 75, 81, 180, 143, 175, 189, 163, 248, 237, 184, 209, 236, 39, 1, + ], + [ + 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, + 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, + 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, + 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, 184, 136, 67, + 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, 111, 15, 134, + 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, 222, 30, 11, 64, + 92, 68, 162, 8, 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, 187, 60, 22, 128, + 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, 117, 120, 44, 256, + 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, 234, 240, 88, 255, + 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1, 146, 242, 123, 225, 211, 223, 176, 253, + 187, 60, 22, 128, 184, 136, 67, 16, 23, 17, 169, 2, 35, 227, 246, 193, 165, 189, 95, 249, + 117, 120, 44, 256, 111, 15, 134, 32, 46, 34, 81, 4, 70, 197, 235, 129, 73, 121, 190, 241, + 234, 240, 88, 255, 222, 30, 11, 64, 92, 68, 162, 8, 140, 137, 213, 1, + ], + [ + 1, 147, 21, 3, 184, 63, 9, 38, 189, 27, 114, 53, 81, 85, 159, 243, 255, 220, 215, 251, 146, + 131, 239, 181, 136, 203, 29, 151, 95, 87, 196, 28, 4, 74, 84, 12, 222, 252, 36, 152, 242, + 108, 199, 212, 67, 83, 122, 201, 249, 109, 89, 233, 70, 10, 185, 210, 30, 41, 116, 90, 123, + 91, 13, 112, 16, 39, 79, 48, 117, 237, 144, 94, 197, 175, 25, 77, 11, 75, 231, 33, 225, 179, + 99, 161, 23, 40, 226, 69, 120, 164, 207, 103, 235, 107, 52, 191, 64, 156, 59, 192, 211, 177, + 62, 119, 17, 186, 100, 51, 44, 43, 153, 132, 129, 202, 139, 130, 92, 160, 133, 19, 223, 142, + 57, 155, 169, 171, 208, 250, 256, 110, 236, 254, 73, 194, 248, 219, 68, 230, 143, 204, 176, + 172, 98, 14, 2, 37, 42, 6, 111, 126, 18, 76, 121, 54, 228, 106, 162, 170, 61, 229, 253, 183, + 173, 245, 35, 5, 221, 105, 15, 149, 58, 45, 190, 174, 135, 56, 8, 148, 168, 24, 187, 247, + 72, 47, 227, 216, 141, 167, 134, 166, 244, 145, 241, 218, 178, 209, 140, 20, 113, 163, 60, + 82, 232, 180, 246, 182, 26, 224, 32, 78, 158, 96, 234, 217, 31, 188, 137, 93, 50, 154, 22, + 150, 205, 66, 193, 101, 198, 65, 46, 80, 195, 138, 240, 71, 157, 206, 213, 214, 104, 125, + 128, 55, 118, 127, 165, 97, 124, 238, 34, 115, 200, 102, 88, 86, 49, 7, 1, + ], + [ + 1, 148, 59, 251, 140, 160, 36, 188, 68, 41, 157, 106, 11, 86, 135, 191, 255, 218, 139, 12, + 234, 194, 185, 138, 121, 175, 200, 45, 235, 85, 244, 132, 4, 78, 236, 233, 46, 126, 144, + 238, 15, 164, 114, 167, 44, 87, 26, 250, 249, 101, 42, 48, 165, 5, 226, 38, 227, 186, 29, + 180, 169, 83, 205, 14, 16, 55, 173, 161, 184, 247, 62, 181, 60, 142, 199, 154, 176, 91, 104, + 229, 225, 147, 168, 192, 146, 20, 133, 152, 137, 230, 116, 206, 162, 75, 49, 56, 64, 220, + 178, 130, 222, 217, 248, 210, 240, 54, 25, 102, 190, 107, 159, 145, 129, 74, 158, 254, 70, + 80, 18, 94, 34, 149, 207, 53, 134, 43, 196, 224, 256, 109, 198, 6, 117, 97, 221, 69, 189, + 216, 100, 151, 246, 171, 122, 66, 2, 39, 118, 245, 23, 63, 72, 119, 136, 82, 57, 212, 22, + 172, 13, 125, 253, 179, 21, 24, 211, 131, 113, 19, 242, 93, 143, 90, 213, 170, 231, 7, 8, + 156, 215, 209, 92, 252, 31, 219, 30, 71, 228, 77, 88, 174, 52, 243, 241, 202, 84, 96, 73, + 10, 195, 76, 197, 115, 58, 103, 81, 166, 153, 28, 32, 110, 89, 65, 111, 237, 124, 105, 120, + 27, 141, 51, 95, 182, 208, 201, 193, 37, 79, 127, 35, 40, 9, 47, 17, 203, 232, 155, 67, 150, + 98, 112, 128, 183, 99, 3, 187, 177, 239, 163, 223, 108, 50, 204, 123, 214, 61, 33, 1, + ], + [ + 1, 149, 99, 102, 35, 75, 124, 229, 197, 55, 228, 48, 213, 126, 13, 138, 2, 41, 198, 204, 70, + 150, 248, 201, 137, 110, 199, 96, 169, 252, 26, 19, 4, 82, 139, 151, 140, 43, 239, 145, 17, + 220, 141, 192, 81, 247, 52, 38, 8, 164, 21, 45, 23, 86, 221, 33, 34, 183, 25, 127, 162, 237, + 104, 76, 16, 71, 42, 90, 46, 172, 185, 66, 68, 109, 50, 254, 67, 217, 208, 152, 32, 142, 84, + 180, 92, 87, 113, 132, 136, 218, 100, 251, 134, 177, 159, 47, 64, 27, 168, 103, 184, 174, + 226, 7, 15, 179, 200, 245, 11, 97, 61, 94, 128, 54, 79, 206, 111, 91, 195, 14, 30, 101, 143, + 233, 22, 194, 122, 188, 256, 108, 158, 155, 222, 182, 133, 28, 60, 202, 29, 209, 44, 131, + 244, 119, 255, 216, 59, 53, 187, 107, 9, 56, 120, 147, 58, 161, 88, 5, 231, 238, 253, 175, + 118, 106, 117, 214, 18, 112, 240, 37, 116, 65, 176, 10, 205, 219, 249, 93, 236, 212, 234, + 171, 36, 224, 223, 74, 232, 130, 95, 20, 153, 181, 241, 186, 215, 167, 211, 85, 72, 191, + 189, 148, 207, 3, 190, 40, 49, 105, 225, 115, 173, 77, 165, 170, 144, 125, 121, 39, 157, 6, + 123, 80, 98, 210, 193, 230, 89, 154, 73, 83, 31, 250, 242, 78, 57, 12, 246, 160, 196, 163, + 129, 203, 178, 51, 146, 166, 62, 243, 227, 156, 114, 24, 235, 63, 135, 69, 1, + ], + [ + 1, 150, 141, 76, 92, 179, 122, 53, 240, 20, 173, 250, 235, 41, 239, 127, 32, 174, 143, 119, + 117, 74, 49, 154, 227, 126, 139, 33, 67, 27, 195, 209, 253, 171, 207, 210, 146, 55, 26, 45, + 68, 177, 79, 28, 88, 93, 72, 6, 129, 75, 199, 38, 46, 218, 61, 155, 120, 10, 215, 125, 246, + 149, 248, 192, 16, 87, 200, 188, 187, 37, 153, 77, 242, 63, 198, 145, 162, 142, 226, 233, + 255, 214, 232, 105, 73, 156, 13, 151, 34, 217, 168, 14, 44, 175, 36, 3, 193, 166, 228, 19, + 23, 109, 159, 206, 60, 5, 236, 191, 123, 203, 124, 96, 8, 172, 100, 94, 222, 147, 205, 167, + 121, 160, 99, 201, 81, 71, 113, 245, 256, 107, 116, 181, 165, 78, 135, 204, 17, 237, 84, 7, + 22, 216, 18, 130, 225, 83, 114, 138, 140, 183, 208, 103, 30, 131, 118, 224, 190, 230, 62, + 48, 4, 86, 50, 47, 111, 202, 231, 212, 189, 80, 178, 229, 169, 164, 185, 251, 128, 182, 58, + 219, 211, 39, 196, 102, 137, 247, 42, 132, 11, 108, 9, 65, 241, 170, 57, 69, 70, 220, 104, + 180, 15, 194, 59, 112, 95, 115, 31, 24, 2, 43, 25, 152, 184, 101, 244, 106, 223, 40, 89, + 243, 213, 82, 221, 254, 64, 91, 29, 238, 234, 148, 98, 51, 197, 252, 21, 66, 134, 54, 133, + 161, 249, 85, 157, 163, 35, 110, 52, 90, 136, 97, 158, 56, 176, 186, 144, 12, 1, + ], + [ + 1, 151, 185, 179, 44, 219, 173, 166, 137, 127, 159, 108, 117, 191, 57, 126, 8, 180, 195, + 147, 95, 210, 99, 43, 68, 245, 244, 93, 165, 243, 199, 237, 64, 155, 18, 148, 246, 138, 21, + 87, 30, 161, 153, 230, 35, 145, 50, 97, 255, 212, 144, 156, 169, 76, 168, 182, 240, 3, 196, + 41, 23, 132, 143, 5, 241, 154, 124, 220, 67, 94, 59, 171, 121, 24, 26, 71, 184, 28, 116, 40, + 129, 204, 221, 218, 22, 238, 215, 83, 197, 192, 208, 54, 187, 224, 157, 63, 4, 90, 226, 202, + 176, 105, 178, 150, 34, 251, 122, 175, 211, 250, 228, 247, 32, 206, 9, 74, 123, 69, 139, + 172, 15, 209, 205, 115, 146, 201, 25, 177, 256, 106, 72, 78, 213, 38, 84, 91, 120, 130, 98, + 149, 140, 66, 200, 131, 249, 77, 62, 110, 162, 47, 158, 214, 189, 12, 13, 164, 92, 14, 58, + 20, 193, 102, 239, 109, 11, 119, 236, 170, 227, 96, 104, 27, 222, 112, 207, 160, 2, 45, 113, + 101, 88, 181, 89, 75, 17, 254, 61, 216, 234, 125, 114, 252, 16, 103, 133, 37, 190, 163, 198, + 86, 136, 233, 231, 186, 73, 229, 141, 217, 128, 53, 36, 39, 235, 19, 42, 174, 60, 65, 49, + 203, 70, 33, 100, 194, 253, 167, 31, 55, 81, 152, 79, 107, 223, 6, 135, 82, 46, 7, 29, 10, + 225, 51, 248, 183, 134, 188, 118, 85, 242, 48, 52, 142, 111, 56, 232, 80, 1, + ], + [ + 1, 152, 231, 160, 162, 209, 157, 220, 30, 191, 248, 174, 234, 102, 84, 175, 129, 76, 244, + 80, 81, 233, 207, 110, 15, 224, 124, 87, 117, 51, 42, 216, 193, 38, 122, 40, 169, 245, 232, + 55, 136, 112, 62, 172, 187, 154, 21, 108, 225, 19, 61, 20, 213, 251, 116, 156, 68, 56, 31, + 86, 222, 77, 139, 54, 241, 138, 159, 10, 235, 254, 58, 78, 34, 28, 144, 43, 111, 167, 198, + 27, 249, 69, 208, 5, 246, 127, 29, 39, 17, 14, 72, 150, 184, 212, 99, 142, 253, 163, 104, + 131, 123, 192, 143, 148, 137, 7, 36, 75, 92, 106, 178, 71, 255, 210, 52, 194, 190, 96, 200, + 74, 197, 132, 18, 166, 46, 53, 89, 164, 256, 105, 26, 97, 95, 48, 100, 37, 227, 66, 9, 83, + 23, 155, 173, 82, 128, 181, 13, 177, 176, 24, 50, 147, 242, 33, 133, 170, 140, 206, 215, 41, + 64, 219, 135, 217, 88, 12, 25, 202, 121, 145, 195, 85, 70, 103, 236, 149, 32, 238, 196, 237, + 44, 6, 141, 101, 189, 201, 226, 171, 35, 180, 118, 203, 16, 119, 98, 247, 22, 3, 199, 179, + 223, 229, 113, 214, 146, 90, 59, 230, 8, 188, 49, 252, 11, 130, 228, 218, 240, 243, 185, + 107, 73, 45, 158, 115, 4, 94, 153, 126, 134, 65, 114, 109, 120, 250, 221, 182, 165, 151, 79, + 186, 2, 47, 205, 63, 67, 161, 57, 183, 60, 125, 239, 91, 211, 204, 168, 93, 1, + ], + [ + 1, 153, 22, 25, 227, 36, 111, 21, 129, 205, 11, 141, 242, 18, 184, 139, 193, 231, 134, 199, + 121, 9, 92, 198, 225, 244, 67, 228, 189, 133, 46, 99, 241, 122, 162, 114, 223, 195, 23, 178, + 249, 61, 81, 57, 240, 226, 140, 89, 253, 159, 169, 157, 120, 113, 70, 173, 255, 208, 213, + 207, 60, 185, 35, 215, 256, 104, 235, 232, 30, 221, 146, 236, 128, 52, 246, 116, 15, 239, + 73, 118, 64, 26, 123, 58, 136, 248, 165, 59, 32, 13, 190, 29, 68, 124, 211, 158, 16, 135, + 95, 143, 34, 62, 234, 79, 8, 196, 176, 200, 17, 31, 117, 168, 4, 98, 88, 100, 137, 144, 187, + 84, 2, 49, 44, 50, 197, 72, 222, 42, 1, 153, 22, 25, 227, 36, 111, 21, 129, 205, 11, 141, + 242, 18, 184, 139, 193, 231, 134, 199, 121, 9, 92, 198, 225, 244, 67, 228, 189, 133, 46, 99, + 241, 122, 162, 114, 223, 195, 23, 178, 249, 61, 81, 57, 240, 226, 140, 89, 253, 159, 169, + 157, 120, 113, 70, 173, 255, 208, 213, 207, 60, 185, 35, 215, 256, 104, 235, 232, 30, 221, + 146, 236, 128, 52, 246, 116, 15, 239, 73, 118, 64, 26, 123, 58, 136, 248, 165, 59, 32, 13, + 190, 29, 68, 124, 211, 158, 16, 135, 95, 143, 34, 62, 234, 79, 8, 196, 176, 200, 17, 31, + 117, 168, 4, 98, 88, 100, 137, 144, 187, 84, 2, 49, 44, 50, 197, 72, 222, 42, 1, + ], + [ + 1, 154, 72, 37, 44, 94, 84, 86, 137, 24, 98, 186, 117, 28, 200, 217, 8, 204, 62, 39, 95, + 238, 158, 174, 68, 192, 13, 203, 165, 224, 58, 194, 64, 90, 239, 55, 246, 105, 236, 107, 30, + 251, 104, 82, 35, 250, 207, 10, 255, 206, 113, 183, 169, 69, 89, 85, 240, 209, 61, 142, 23, + 201, 114, 80, 241, 106, 133, 179, 67, 38, 198, 166, 121, 130, 231, 108, 184, 66, 141, 126, + 129, 77, 36, 147, 22, 47, 42, 43, 197, 12, 49, 93, 187, 14, 100, 237, 4, 102, 31, 148, 176, + 119, 79, 87, 34, 96, 135, 230, 211, 112, 29, 97, 32, 45, 248, 156, 123, 181, 118, 182, 15, + 254, 52, 41, 146, 125, 232, 5, 256, 103, 185, 220, 213, 163, 173, 171, 120, 233, 159, 71, + 140, 229, 57, 40, 249, 53, 195, 218, 162, 19, 99, 83, 189, 65, 244, 54, 92, 33, 199, 63, + 193, 167, 18, 202, 11, 152, 21, 150, 227, 6, 153, 175, 222, 7, 50, 247, 2, 51, 144, 74, 88, + 188, 168, 172, 17, 48, 196, 115, 234, 56, 143, 177, 16, 151, 124, 78, 190, 219, 59, 91, 136, + 127, 26, 149, 73, 191, 116, 131, 128, 180, 221, 110, 235, 210, 215, 214, 60, 245, 208, 164, + 70, 243, 157, 20, 253, 155, 226, 109, 81, 138, 178, 170, 223, 161, 122, 27, 46, 145, 228, + 160, 225, 212, 9, 101, 134, 76, 139, 75, 242, 3, 205, 216, 111, 132, 25, 252, 1, + ], + [ + 1, 155, 124, 202, 213, 119, 198, 107, 137, 161, 26, 175, 140, 112, 141, 10, 8, 212, 221, 74, + 162, 181, 42, 85, 68, 3, 208, 115, 92, 125, 100, 80, 64, 154, 226, 78, 11, 163, 79, 166, 30, + 24, 122, 149, 222, 229, 29, 126, 255, 204, 9, 110, 88, 19, 118, 43, 240, 192, 205, 164, 234, + 33, 232, 237, 241, 90, 72, 109, 190, 152, 173, 87, 121, 251, 98, 27, 73, 7, 57, 97, 129, + 206, 62, 101, 235, 188, 99, 182, 197, 209, 13, 216, 70, 56, 199, 5, 4, 106, 239, 37, 81, + 219, 21, 171, 34, 130, 104, 186, 46, 191, 50, 40, 32, 77, 113, 39, 134, 210, 168, 83, 15, + 12, 61, 203, 111, 243, 143, 63, 256, 102, 133, 55, 44, 138, 59, 150, 120, 96, 231, 82, 117, + 145, 116, 247, 249, 45, 36, 183, 95, 76, 215, 172, 189, 254, 49, 142, 165, 132, 157, 177, + 193, 103, 31, 179, 246, 94, 178, 91, 227, 233, 135, 108, 35, 28, 228, 131, 2, 53, 248, 147, + 169, 238, 139, 214, 17, 65, 52, 93, 23, 224, 25, 20, 16, 167, 185, 148, 67, 105, 84, 170, + 136, 6, 159, 230, 184, 250, 200, 160, 128, 51, 195, 156, 22, 69, 158, 75, 60, 48, 244, 41, + 187, 201, 58, 252, 253, 151, 18, 220, 176, 38, 236, 86, 223, 127, 153, 71, 211, 66, 207, + 217, 225, 180, 144, 218, 123, 47, 89, 174, 242, 245, 196, 54, 146, 14, 114, 194, 1, + ], + [ + 1, 156, 178, 12, 73, 80, 144, 105, 189, 186, 232, 212, 176, 214, 231, 56, 255, 202, 158, + 233, 111, 97, 226, 47, 136, 142, 50, 90, 162, 86, 52, 145, 4, 110, 198, 48, 35, 63, 62, 163, + 242, 230, 157, 77, 190, 85, 153, 224, 249, 37, 118, 161, 187, 131, 133, 188, 30, 54, 200, + 103, 134, 87, 208, 66, 16, 183, 21, 192, 140, 252, 248, 138, 197, 149, 114, 51, 246, 83, 98, + 125, 225, 148, 215, 130, 234, 10, 18, 238, 120, 216, 29, 155, 22, 91, 61, 7, 64, 218, 84, + 254, 46, 237, 221, 38, 17, 82, 199, 204, 213, 75, 135, 243, 129, 78, 89, 6, 165, 40, 72, + 181, 223, 93, 116, 106, 88, 107, 244, 28, 256, 101, 79, 245, 184, 177, 113, 152, 68, 71, 25, + 45, 81, 43, 26, 201, 2, 55, 99, 24, 146, 160, 31, 210, 121, 115, 207, 167, 95, 171, 205, + 112, 253, 147, 59, 209, 222, 194, 195, 94, 15, 27, 100, 180, 67, 172, 104, 33, 8, 220, 139, + 96, 70, 126, 124, 69, 227, 203, 57, 154, 123, 170, 49, 191, 241, 74, 236, 65, 117, 5, 9, + 119, 60, 108, 143, 206, 11, 174, 159, 132, 32, 109, 42, 127, 23, 247, 239, 19, 137, 41, 228, + 102, 235, 166, 196, 250, 193, 39, 173, 3, 211, 20, 36, 219, 240, 175, 58, 53, 44, 182, 122, + 14, 128, 179, 168, 251, 92, 217, 185, 76, 34, 164, 141, 151, 169, 150, 13, 229, 1, + ], + [ + 1, 157, 234, 244, 15, 42, 169, 62, 225, 116, 222, 159, 34, 198, 246, 72, 253, 143, 92, 52, + 197, 89, 95, 9, 128, 50, 140, 135, 121, 236, 44, 226, 16, 199, 146, 49, 240, 158, 134, 221, + 2, 57, 211, 231, 30, 84, 81, 124, 193, 232, 187, 61, 68, 139, 235, 144, 249, 29, 184, 104, + 137, 178, 190, 18, 256, 100, 23, 13, 242, 215, 88, 195, 32, 141, 35, 98, 223, 59, 11, 185, + 4, 114, 165, 205, 60, 168, 162, 248, 129, 207, 117, 122, 136, 21, 213, 31, 241, 58, 111, + 208, 17, 99, 123, 36, 255, 200, 46, 26, 227, 173, 176, 133, 64, 25, 70, 196, 189, 118, 22, + 113, 8, 228, 73, 153, 120, 79, 67, 239, 1, 157, 234, 244, 15, 42, 169, 62, 225, 116, 222, + 159, 34, 198, 246, 72, 253, 143, 92, 52, 197, 89, 95, 9, 128, 50, 140, 135, 121, 236, 44, + 226, 16, 199, 146, 49, 240, 158, 134, 221, 2, 57, 211, 231, 30, 84, 81, 124, 193, 232, 187, + 61, 68, 139, 235, 144, 249, 29, 184, 104, 137, 178, 190, 18, 256, 100, 23, 13, 242, 215, 88, + 195, 32, 141, 35, 98, 223, 59, 11, 185, 4, 114, 165, 205, 60, 168, 162, 248, 129, 207, 117, + 122, 136, 21, 213, 31, 241, 58, 111, 208, 17, 99, 123, 36, 255, 200, 46, 26, 227, 173, 176, + 133, 64, 25, 70, 196, 189, 118, 22, 113, 8, 228, 73, 153, 120, 79, 67, 239, 1, + ], + [ + 1, 158, 35, 133, 197, 29, 213, 244, 2, 59, 70, 9, 137, 58, 169, 231, 4, 118, 140, 18, 17, + 116, 81, 205, 8, 236, 23, 36, 34, 232, 162, 153, 16, 215, 46, 72, 68, 207, 67, 49, 32, 173, + 92, 144, 136, 157, 134, 98, 64, 89, 184, 31, 15, 57, 11, 196, 128, 178, 111, 62, 30, 114, + 22, 135, 256, 99, 222, 124, 60, 228, 44, 13, 255, 198, 187, 248, 120, 199, 88, 26, 253, 139, + 117, 239, 240, 141, 176, 52, 249, 21, 234, 221, 223, 25, 95, 104, 241, 42, 211, 185, 189, + 50, 190, 208, 225, 84, 165, 113, 121, 100, 123, 159, 193, 168, 73, 226, 242, 200, 246, 61, + 129, 79, 146, 195, 227, 143, 235, 122, 1, 158, 35, 133, 197, 29, 213, 244, 2, 59, 70, 9, + 137, 58, 169, 231, 4, 118, 140, 18, 17, 116, 81, 205, 8, 236, 23, 36, 34, 232, 162, 153, 16, + 215, 46, 72, 68, 207, 67, 49, 32, 173, 92, 144, 136, 157, 134, 98, 64, 89, 184, 31, 15, 57, + 11, 196, 128, 178, 111, 62, 30, 114, 22, 135, 256, 99, 222, 124, 60, 228, 44, 13, 255, 198, + 187, 248, 120, 199, 88, 26, 253, 139, 117, 239, 240, 141, 176, 52, 249, 21, 234, 221, 223, + 25, 95, 104, 241, 42, 211, 185, 189, 50, 190, 208, 225, 84, 165, 113, 121, 100, 123, 159, + 193, 168, 73, 226, 242, 200, 246, 61, 129, 79, 146, 195, 227, 143, 235, 122, 1, + ], + [ + 1, 159, 95, 199, 30, 144, 23, 59, 129, 208, 176, 228, 15, 72, 140, 158, 193, 104, 88, 114, + 136, 36, 70, 79, 225, 52, 44, 57, 68, 18, 35, 168, 241, 26, 22, 157, 34, 9, 146, 84, 249, + 13, 11, 207, 17, 133, 73, 42, 253, 135, 134, 232, 137, 195, 165, 21, 255, 196, 67, 116, 197, + 226, 211, 139, 256, 98, 162, 58, 227, 113, 234, 198, 128, 49, 81, 29, 242, 185, 117, 99, 64, + 153, 169, 143, 121, 221, 187, 178, 32, 205, 213, 200, 189, 239, 222, 89, 16, 231, 235, 100, + 223, 248, 111, 173, 8, 244, 246, 50, 240, 124, 184, 215, 4, 122, 123, 25, 120, 62, 92, 236, + 2, 61, 190, 141, 60, 31, 46, 118, 1, 159, 95, 199, 30, 144, 23, 59, 129, 208, 176, 228, 15, + 72, 140, 158, 193, 104, 88, 114, 136, 36, 70, 79, 225, 52, 44, 57, 68, 18, 35, 168, 241, 26, + 22, 157, 34, 9, 146, 84, 249, 13, 11, 207, 17, 133, 73, 42, 253, 135, 134, 232, 137, 195, + 165, 21, 255, 196, 67, 116, 197, 226, 211, 139, 256, 98, 162, 58, 227, 113, 234, 198, 128, + 49, 81, 29, 242, 185, 117, 99, 64, 153, 169, 143, 121, 221, 187, 178, 32, 205, 213, 200, + 189, 239, 222, 89, 16, 231, 235, 100, 223, 248, 111, 173, 8, 244, 246, 50, 240, 124, 184, + 215, 4, 122, 123, 25, 120, 62, 92, 236, 2, 61, 190, 141, 60, 31, 46, 118, 1, + ], + [ + 1, 160, 157, 191, 234, 175, 244, 233, 15, 87, 42, 38, 169, 55, 62, 154, 225, 20, 116, 56, + 222, 54, 159, 254, 34, 43, 198, 69, 246, 39, 72, 212, 253, 131, 143, 7, 92, 71, 52, 96, 197, + 166, 89, 105, 95, 37, 9, 155, 128, 177, 50, 33, 140, 41, 135, 12, 121, 85, 236, 238, 44, + 101, 226, 180, 16, 247, 199, 229, 146, 230, 49, 130, 240, 107, 158, 94, 134, 109, 221, 151, + 2, 63, 57, 125, 211, 93, 231, 209, 30, 174, 84, 76, 81, 110, 124, 51, 193, 40, 232, 112, + 187, 108, 61, 251, 68, 86, 139, 138, 235, 78, 144, 167, 249, 5, 29, 14, 184, 142, 104, 192, + 137, 75, 178, 210, 190, 74, 18, 53, 256, 97, 100, 66, 23, 82, 13, 24, 242, 170, 215, 219, + 88, 202, 195, 103, 32, 237, 141, 201, 35, 203, 98, 3, 223, 214, 59, 188, 11, 218, 185, 45, + 4, 126, 114, 250, 165, 186, 205, 161, 60, 91, 168, 152, 162, 220, 248, 102, 129, 80, 207, + 224, 117, 216, 122, 245, 136, 172, 21, 19, 213, 156, 31, 77, 241, 10, 58, 28, 111, 27, 208, + 127, 17, 150, 99, 163, 123, 148, 36, 106, 255, 194, 200, 132, 46, 164, 26, 48, 227, 83, 173, + 181, 176, 147, 133, 206, 64, 217, 25, 145, 70, 149, 196, 6, 189, 171, 118, 119, 22, 179, + 113, 90, 8, 252, 228, 243, 73, 115, 153, 65, 120, 182, 79, 47, 67, 183, 239, 204, 1, + ], + [ + 1, 161, 221, 115, 11, 229, 118, 237, 121, 206, 13, 37, 46, 210, 143, 150, 249, 254, 31, 108, + 169, 224, 84, 160, 60, 151, 153, 218, 146, 119, 141, 85, 64, 24, 9, 164, 190, 7, 99, 5, 34, + 77, 61, 55, 117, 76, 157, 91, 2, 65, 185, 230, 22, 201, 236, 217, 242, 155, 26, 74, 92, 163, + 29, 43, 241, 251, 62, 216, 81, 191, 168, 63, 120, 45, 49, 179, 35, 238, 25, 170, 128, 48, + 18, 71, 123, 14, 198, 10, 68, 154, 122, 110, 234, 152, 57, 182, 4, 130, 113, 203, 44, 145, + 215, 177, 227, 53, 52, 148, 184, 69, 58, 86, 225, 245, 124, 175, 162, 125, 79, 126, 240, 90, + 98, 101, 70, 219, 50, 83, 256, 96, 36, 142, 246, 28, 139, 20, 136, 51, 244, 220, 211, 47, + 114, 107, 8, 3, 226, 149, 88, 33, 173, 97, 197, 106, 104, 39, 111, 138, 116, 172, 193, 233, + 248, 93, 67, 250, 158, 252, 223, 180, 196, 202, 140, 181, 100, 166, 255, 192, 72, 27, 235, + 56, 21, 40, 15, 102, 231, 183, 165, 94, 228, 214, 16, 6, 195, 41, 176, 66, 89, 194, 137, + 212, 208, 78, 222, 19, 232, 87, 129, 209, 239, 186, 134, 243, 59, 247, 189, 103, 135, 147, + 23, 105, 200, 75, 253, 127, 144, 54, 213, 112, 42, 80, 30, 204, 205, 109, 73, 188, 199, 171, + 32, 12, 133, 82, 95, 132, 178, 131, 17, 167, 159, 156, 187, 38, 207, 174, 1, + ], + [ + 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, + 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, + 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, + 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, 225, 213, 68, 222, + 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, 46, 256, 95, 227, + 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, 146, 8, 11, 240, 73, + 4, 134, 120, 165, 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, 193, 169, 136, 187, + 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, 92, 255, 190, 197, + 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, 35, 16, 22, 223, + 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1, 162, 30, 234, 129, 81, 15, 117, + 193, 169, 136, 187, 225, 213, 68, 222, 241, 235, 34, 111, 249, 246, 17, 184, 253, 123, 137, + 92, 255, 190, 197, 46, 256, 95, 227, 23, 128, 176, 242, 140, 64, 88, 121, 70, 32, 44, 189, + 35, 16, 22, 223, 146, 8, 11, 240, 73, 4, 134, 120, 165, 2, 67, 60, 211, 1, + ], + [ + 1, 163, 98, 40, 95, 65, 58, 202, 30, 7, 113, 172, 23, 151, 198, 149, 129, 210, 49, 20, 176, + 161, 29, 101, 15, 132, 185, 86, 140, 204, 99, 203, 193, 105, 153, 10, 88, 209, 143, 179, + 136, 66, 221, 43, 70, 102, 178, 230, 225, 181, 205, 5, 44, 233, 200, 218, 68, 33, 239, 150, + 35, 51, 89, 115, 241, 219, 231, 131, 22, 245, 100, 109, 34, 145, 248, 75, 146, 154, 173, + 186, 249, 238, 244, 194, 11, 251, 50, 183, 17, 201, 124, 166, 73, 77, 215, 93, 253, 119, + 122, 97, 134, 254, 25, 220, 137, 229, 62, 83, 165, 167, 236, 175, 255, 188, 61, 177, 67, + 127, 141, 110, 197, 243, 31, 170, 211, 212, 118, 216, 256, 94, 159, 217, 162, 192, 199, 55, + 227, 250, 144, 85, 234, 106, 59, 108, 128, 47, 208, 237, 81, 96, 228, 156, 242, 125, 72, + 171, 117, 53, 158, 54, 64, 152, 104, 247, 169, 48, 114, 78, 121, 191, 36, 214, 187, 155, 79, + 27, 32, 76, 52, 252, 213, 24, 57, 39, 189, 224, 18, 107, 222, 206, 168, 142, 16, 38, 26, + 126, 235, 12, 157, 148, 223, 112, 9, 182, 111, 103, 84, 71, 8, 19, 13, 63, 246, 6, 207, 74, + 240, 56, 133, 91, 184, 180, 42, 164, 4, 138, 135, 160, 123, 3, 232, 37, 120, 28, 195, 174, + 92, 90, 21, 82, 2, 69, 196, 80, 190, 130, 116, 147, 60, 14, 226, 87, 46, 45, 139, 41, 1, + ], + [ + 1, 164, 168, 53, 211, 166, 239, 132, 60, 74, 57, 96, 67, 194, 205, 210, 2, 71, 79, 106, 165, + 75, 221, 7, 120, 148, 114, 192, 134, 131, 153, 163, 4, 142, 158, 212, 73, 150, 185, 14, 240, + 39, 228, 127, 11, 5, 49, 69, 8, 27, 59, 167, 146, 43, 113, 28, 223, 78, 199, 254, 22, 10, + 98, 138, 16, 54, 118, 77, 35, 86, 226, 56, 189, 156, 141, 251, 44, 20, 196, 19, 32, 108, + 236, 154, 70, 172, 195, 112, 121, 55, 25, 245, 88, 40, 135, 38, 64, 216, 215, 51, 140, 87, + 133, 224, 242, 110, 50, 233, 176, 80, 13, 76, 128, 175, 173, 102, 23, 174, 9, 191, 227, 220, + 100, 209, 95, 160, 26, 152, 256, 93, 89, 204, 46, 91, 18, 125, 197, 183, 200, 161, 190, 63, + 52, 47, 255, 186, 178, 151, 92, 182, 36, 250, 137, 109, 143, 65, 123, 126, 104, 94, 253, + 115, 99, 45, 184, 107, 72, 243, 17, 218, 29, 130, 246, 252, 208, 188, 249, 230, 198, 90, + 111, 214, 144, 229, 34, 179, 58, 3, 235, 247, 159, 119, 241, 203, 139, 180, 222, 171, 31, + 201, 68, 101, 116, 6, 213, 237, 61, 238, 225, 149, 21, 103, 187, 85, 62, 145, 136, 202, 232, + 12, 169, 217, 122, 219, 193, 41, 42, 206, 117, 170, 124, 33, 15, 147, 207, 24, 81, 177, 244, + 181, 129, 82, 84, 155, 234, 83, 248, 66, 30, 37, 157, 48, 162, 97, 231, 105, 1, + ], + [ + 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, + 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, + 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, + 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, 211, 120, 11, + 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, 92, 17, 235, + 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, 223, 44, 64, + 23, 197, 123, 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, 68, 169, 129, + 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, 121, 176, 256, + 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, 15, 162, 2, 73, + 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1, 165, 240, 22, 32, 140, 227, 190, 253, 111, + 68, 169, 129, 211, 120, 11, 16, 70, 242, 95, 255, 184, 34, 213, 193, 234, 60, 134, 8, 35, + 121, 176, 256, 92, 17, 235, 225, 117, 30, 67, 4, 146, 189, 88, 128, 46, 137, 246, 241, 187, + 15, 162, 2, 73, 223, 44, 64, 23, 197, 123, 249, 222, 136, 81, 1, + ], + [ + 1, 166, 57, 210, 165, 148, 153, 212, 240, 5, 59, 28, 22, 54, 226, 251, 32, 172, 25, 38, 140, + 110, 13, 102, 227, 160, 89, 125, 190, 186, 36, 65, 253, 107, 29, 188, 111, 179, 159, 180, + 68, 237, 21, 145, 169, 41, 124, 24, 129, 83, 157, 105, 211, 74, 205, 106, 120, 131, 158, 14, + 11, 27, 113, 254, 16, 86, 141, 19, 70, 55, 135, 51, 242, 80, 173, 191, 95, 93, 18, 161, 255, + 182, 143, 94, 184, 218, 208, 90, 34, 247, 139, 201, 213, 149, 62, 12, 193, 170, 207, 181, + 234, 37, 231, 53, 60, 194, 79, 7, 134, 142, 185, 127, 8, 43, 199, 138, 35, 156, 196, 154, + 121, 40, 215, 224, 176, 175, 9, 209, 256, 91, 200, 47, 92, 109, 104, 45, 17, 252, 198, 229, + 235, 203, 31, 6, 225, 85, 232, 219, 117, 147, 244, 155, 30, 97, 168, 132, 67, 71, 221, 192, + 4, 150, 228, 69, 146, 78, 98, 77, 189, 20, 236, 112, 88, 216, 133, 233, 128, 174, 100, 152, + 46, 183, 52, 151, 137, 126, 99, 243, 246, 230, 144, 3, 241, 171, 116, 238, 187, 202, 122, + 206, 15, 177, 84, 66, 162, 164, 239, 96, 2, 75, 114, 163, 73, 39, 49, 167, 223, 10, 118, 56, + 44, 108, 195, 245, 64, 87, 50, 76, 23, 220, 26, 204, 197, 63, 178, 250, 123, 115, 72, 130, + 249, 214, 58, 119, 222, 101, 61, 103, 136, 217, 42, 33, 81, 82, 248, 48, 1, + ], + [ + 1, 167, 133, 109, 213, 105, 59, 87, 137, 6, 231, 27, 140, 250, 116, 97, 8, 51, 36, 101, 162, + 69, 215, 182, 68, 48, 49, 216, 92, 201, 157, 5, 64, 151, 31, 37, 11, 38, 178, 171, 30, 127, + 135, 186, 222, 66, 228, 40, 255, 180, 248, 39, 88, 47, 139, 83, 240, 245, 52, 203, 234, 14, + 25, 63, 241, 155, 185, 55, 190, 119, 84, 150, 121, 161, 159, 82, 73, 112, 200, 247, 129, + 212, 195, 183, 235, 181, 158, 172, 197, 3, 244, 142, 70, 125, 58, 177, 4, 154, 18, 179, 81, + 163, 236, 91, 34, 24, 153, 108, 46, 229, 207, 131, 32, 204, 144, 147, 134, 19, 89, 214, 15, + 192, 196, 93, 111, 33, 114, 20, 256, 90, 124, 148, 44, 152, 198, 170, 120, 251, 26, 230, + 117, 7, 141, 160, 249, 206, 221, 156, 95, 188, 42, 75, 189, 209, 208, 41, 165, 56, 100, 252, + 193, 106, 226, 220, 246, 219, 79, 86, 227, 130, 122, 71, 35, 191, 29, 217, 2, 77, 9, 218, + 169, 210, 118, 174, 17, 12, 205, 54, 23, 243, 232, 194, 16, 102, 72, 202, 67, 138, 173, 107, + 136, 96, 98, 175, 184, 145, 57, 10, 128, 45, 62, 74, 22, 76, 99, 85, 60, 254, 13, 115, 187, + 132, 199, 80, 253, 103, 239, 78, 176, 94, 21, 166, 223, 233, 104, 149, 211, 28, 50, 126, + 225, 53, 113, 110, 123, 238, 168, 43, 242, 65, 61, 164, 146, 224, 143, 237, 1, + ], + [ + 1, 168, 211, 239, 60, 57, 67, 205, 2, 79, 165, 221, 120, 114, 134, 153, 4, 158, 73, 185, + 240, 228, 11, 49, 8, 59, 146, 113, 223, 199, 22, 98, 16, 118, 35, 226, 189, 141, 44, 196, + 32, 236, 70, 195, 121, 25, 88, 135, 64, 215, 140, 133, 242, 50, 176, 13, 128, 173, 23, 9, + 227, 100, 95, 26, 256, 89, 46, 18, 197, 200, 190, 52, 255, 178, 92, 36, 137, 143, 123, 104, + 253, 99, 184, 72, 17, 29, 246, 208, 249, 198, 111, 144, 34, 58, 235, 159, 241, 139, 222, 31, + 68, 116, 213, 61, 225, 21, 187, 62, 136, 232, 169, 122, 193, 42, 117, 124, 15, 207, 81, 244, + 129, 84, 234, 248, 30, 157, 162, 231, 1, 168, 211, 239, 60, 57, 67, 205, 2, 79, 165, 221, + 120, 114, 134, 153, 4, 158, 73, 185, 240, 228, 11, 49, 8, 59, 146, 113, 223, 199, 22, 98, + 16, 118, 35, 226, 189, 141, 44, 196, 32, 236, 70, 195, 121, 25, 88, 135, 64, 215, 140, 133, + 242, 50, 176, 13, 128, 173, 23, 9, 227, 100, 95, 26, 256, 89, 46, 18, 197, 200, 190, 52, + 255, 178, 92, 36, 137, 143, 123, 104, 253, 99, 184, 72, 17, 29, 246, 208, 249, 198, 111, + 144, 34, 58, 235, 159, 241, 139, 222, 31, 68, 116, 213, 61, 225, 21, 187, 62, 136, 232, 169, + 122, 193, 42, 117, 124, 15, 207, 81, 244, 129, 84, 234, 248, 30, 157, 162, 231, 1, + ], + [ + 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, + 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, + 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, + 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, 11, 60, 117, 241, + 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, 223, 165, 129, + 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, 190, 242, 35, 4, + 162, 136, 111, 255, 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, 235, 137, 23, 32, + 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, 68, 184, 256, 88, + 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, 30, 187, 249, + 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1, 169, 34, 92, 128, 44, 240, 211, 193, + 235, 137, 23, 32, 11, 60, 117, 241, 123, 227, 70, 8, 67, 15, 222, 253, 95, 121, 146, 2, 81, + 68, 184, 256, 88, 223, 165, 129, 213, 17, 46, 64, 22, 120, 234, 225, 246, 197, 140, 16, 134, + 30, 187, 249, 190, 242, 35, 4, 162, 136, 111, 255, 176, 189, 73, 1, + ], + [ + 1, 170, 116, 188, 92, 220, 135, 77, 240, 194, 84, 145, 235, 115, 18, 233, 32, 43, 114, 105, + 117, 101, 208, 151, 227, 40, 118, 14, 67, 82, 62, 3, 253, 91, 50, 19, 146, 148, 231, 206, + 68, 252, 178, 191, 88, 54, 185, 96, 129, 85, 58, 94, 46, 110, 196, 167, 120, 97, 42, 201, + 246, 186, 9, 245, 16, 150, 57, 181, 187, 179, 104, 204, 242, 20, 59, 7, 162, 41, 31, 130, + 255, 174, 25, 138, 73, 74, 244, 103, 34, 126, 89, 224, 44, 27, 221, 48, 193, 171, 29, 47, + 23, 55, 98, 212, 60, 177, 21, 229, 123, 93, 133, 251, 8, 75, 157, 219, 222, 218, 52, 102, + 121, 10, 158, 132, 81, 149, 144, 65, 256, 87, 141, 69, 165, 37, 122, 180, 17, 63, 173, 112, + 22, 142, 239, 24, 225, 214, 143, 152, 140, 156, 49, 106, 30, 217, 139, 243, 190, 175, 195, + 254, 4, 166, 207, 238, 111, 109, 26, 51, 189, 5, 79, 66, 169, 203, 72, 161, 128, 172, 199, + 163, 211, 147, 61, 90, 137, 160, 215, 56, 11, 71, 248, 12, 241, 107, 200, 76, 70, 78, 153, + 53, 15, 237, 198, 250, 95, 216, 226, 127, 2, 83, 232, 119, 184, 183, 13, 154, 223, 131, 168, + 33, 213, 230, 36, 209, 64, 86, 228, 210, 234, 202, 159, 45, 197, 80, 236, 28, 134, 164, 124, + 6, 249, 182, 100, 38, 35, 39, 205, 155, 136, 247, 99, 125, 176, 108, 113, 192, 1, + ], + [ + 1, 171, 200, 19, 165, 202, 104, 51, 240, 177, 198, 191, 22, 164, 31, 161, 32, 75, 232, 94, + 140, 39, 244, 90, 227, 10, 168, 201, 190, 108, 221, 12, 253, 87, 228, 181, 111, 220, 98, 53, + 68, 63, 236, 7, 169, 115, 133, 127, 129, 214, 100, 138, 211, 101, 52, 154, 120, 217, 99, + 224, 11, 82, 144, 209, 16, 166, 116, 47, 70, 148, 122, 45, 242, 5, 84, 229, 95, 54, 239, 6, + 255, 172, 114, 219, 184, 110, 49, 155, 34, 160, 118, 132, 213, 186, 195, 192, 193, 107, 50, + 69, 234, 179, 26, 77, 60, 237, 178, 112, 134, 41, 72, 233, 8, 83, 58, 152, 35, 74, 61, 151, + 121, 131, 42, 243, 176, 27, 248, 3, 256, 86, 57, 238, 92, 55, 153, 206, 17, 80, 59, 66, 235, + 93, 226, 96, 225, 182, 25, 163, 117, 218, 13, 167, 30, 247, 89, 56, 67, 149, 36, 245, 4, + 170, 29, 76, 146, 37, 159, 204, 189, 194, 21, 250, 88, 142, 124, 130, 128, 43, 157, 119, 46, + 156, 205, 103, 137, 40, 158, 33, 246, 175, 113, 48, 241, 91, 141, 210, 187, 109, 135, 212, + 15, 252, 173, 28, 162, 203, 18, 251, 2, 85, 143, 38, 73, 147, 208, 102, 223, 97, 139, 125, + 44, 71, 62, 65, 64, 150, 207, 188, 23, 78, 231, 180, 197, 20, 79, 145, 123, 216, 185, 24, + 249, 174, 199, 105, 222, 183, 196, 106, 136, 126, 215, 14, 81, 230, 9, 254, 1, + ], + [ + 1, 172, 29, 105, 70, 218, 231, 154, 17, 97, 236, 243, 162, 108, 72, 48, 32, 107, 157, 19, + 184, 37, 196, 45, 30, 20, 99, 66, 44, 115, 248, 251, 253, 83, 141, 94, 234, 156, 104, 155, + 189, 126, 84, 56, 123, 82, 226, 65, 129, 86, 143, 181, 35, 109, 244, 77, 137, 177, 118, 250, + 81, 54, 36, 24, 16, 182, 207, 138, 92, 147, 98, 151, 15, 10, 178, 33, 22, 186, 124, 254, + 255, 170, 199, 47, 117, 78, 52, 206, 223, 63, 42, 28, 190, 41, 113, 161, 193, 43, 200, 219, + 146, 183, 122, 167, 197, 217, 59, 125, 169, 27, 18, 12, 8, 91, 232, 69, 46, 202, 49, 204, + 136, 5, 89, 145, 11, 93, 62, 127, 256, 85, 228, 152, 187, 39, 26, 103, 240, 160, 21, 14, 95, + 149, 185, 209, 225, 150, 100, 238, 73, 220, 61, 212, 227, 237, 158, 191, 213, 142, 9, 6, 4, + 174, 116, 163, 23, 101, 153, 102, 68, 131, 173, 201, 134, 175, 31, 192, 128, 171, 114, 76, + 222, 148, 13, 180, 120, 80, 139, 7, 176, 203, 221, 233, 241, 75, 50, 119, 165, 110, 159, + 106, 242, 247, 79, 224, 235, 71, 133, 3, 2, 87, 58, 210, 140, 179, 205, 51, 34, 194, 215, + 229, 67, 216, 144, 96, 64, 214, 57, 38, 111, 74, 135, 90, 60, 40, 198, 132, 88, 230, 239, + 245, 249, 166, 25, 188, 211, 55, 208, 53, 121, 252, 168, 112, 246, 164, 195, 130, 1, + ], + [ + 1, 173, 117, 195, 68, 199, 246, 153, 255, 168, 23, 124, 121, 116, 22, 208, 4, 178, 211, 9, + 15, 25, 213, 98, 249, 158, 92, 239, 227, 207, 88, 61, 16, 198, 73, 36, 60, 100, 81, 135, + 225, 118, 111, 185, 137, 57, 95, 244, 64, 21, 35, 144, 240, 143, 67, 26, 129, 215, 187, 226, + 34, 228, 123, 205, 256, 84, 140, 62, 189, 58, 11, 104, 2, 89, 234, 133, 136, 141, 235, 49, + 253, 79, 46, 248, 242, 232, 44, 159, 8, 99, 165, 18, 30, 50, 169, 196, 241, 59, 184, 221, + 197, 157, 176, 122, 32, 139, 146, 72, 120, 200, 162, 13, 193, 236, 222, 113, 17, 114, 190, + 231, 128, 42, 70, 31, 223, 29, 134, 52, 1, 173, 117, 195, 68, 199, 246, 153, 255, 168, 23, + 124, 121, 116, 22, 208, 4, 178, 211, 9, 15, 25, 213, 98, 249, 158, 92, 239, 227, 207, 88, + 61, 16, 198, 73, 36, 60, 100, 81, 135, 225, 118, 111, 185, 137, 57, 95, 244, 64, 21, 35, + 144, 240, 143, 67, 26, 129, 215, 187, 226, 34, 228, 123, 205, 256, 84, 140, 62, 189, 58, 11, + 104, 2, 89, 234, 133, 136, 141, 235, 49, 253, 79, 46, 248, 242, 232, 44, 159, 8, 99, 165, + 18, 30, 50, 169, 196, 241, 59, 184, 221, 197, 157, 176, 122, 32, 139, 146, 72, 120, 200, + 162, 13, 193, 236, 222, 113, 17, 114, 190, 231, 128, 42, 70, 31, 223, 29, 134, 52, 1, + ], + [ + 1, 174, 207, 38, 187, 156, 159, 167, 17, 131, 178, 132, 95, 82, 133, 12, 32, 171, 199, 188, + 73, 109, 205, 204, 30, 80, 42, 112, 213, 54, 144, 127, 253, 75, 200, 105, 23, 147, 135, 103, + 189, 247, 59, 243, 134, 186, 239, 209, 129, 87, 232, 19, 222, 78, 208, 212, 137, 194, 89, + 66, 176, 41, 195, 6, 16, 214, 228, 94, 165, 183, 231, 102, 15, 40, 21, 56, 235, 27, 72, 192, + 255, 166, 100, 181, 140, 202, 196, 180, 223, 252, 158, 250, 67, 93, 248, 233, 193, 172, 116, + 138, 111, 39, 104, 106, 197, 97, 173, 33, 88, 149, 226, 3, 8, 107, 114, 47, 211, 220, 244, + 51, 136, 20, 139, 28, 246, 142, 36, 96, 256, 83, 50, 219, 70, 101, 98, 90, 240, 126, 79, + 125, 162, 175, 124, 245, 225, 86, 58, 69, 184, 148, 52, 53, 227, 177, 215, 145, 44, 203, + 113, 130, 4, 182, 57, 152, 234, 110, 122, 154, 68, 10, 198, 14, 123, 71, 18, 48, 128, 170, + 25, 238, 35, 179, 49, 45, 120, 63, 168, 191, 81, 216, 62, 251, 241, 43, 29, 163, 92, 74, 26, + 155, 242, 217, 236, 201, 22, 230, 185, 65, 2, 91, 157, 76, 117, 55, 61, 77, 34, 5, 99, 7, + 190, 164, 9, 24, 64, 85, 141, 119, 146, 218, 153, 151, 60, 160, 84, 224, 169, 108, 31, 254, + 249, 150, 143, 210, 46, 37, 13, 206, 121, 237, 118, 229, 11, 115, 221, 161, 1, + ], + [ + 1, 175, 42, 154, 222, 43, 72, 7, 197, 37, 50, 12, 44, 247, 49, 94, 2, 93, 84, 51, 187, 86, + 144, 14, 137, 74, 100, 24, 88, 237, 98, 188, 4, 186, 168, 102, 117, 172, 31, 28, 17, 148, + 200, 48, 176, 217, 196, 119, 8, 115, 79, 204, 234, 87, 62, 56, 34, 39, 143, 96, 95, 177, + 135, 238, 16, 230, 158, 151, 211, 174, 124, 112, 68, 78, 29, 192, 190, 97, 13, 219, 32, 203, + 59, 45, 165, 91, 248, 224, 136, 156, 58, 127, 123, 194, 26, 181, 64, 149, 118, 90, 73, 182, + 239, 191, 15, 55, 116, 254, 246, 131, 52, 105, 128, 41, 236, 180, 146, 107, 221, 125, 30, + 110, 232, 251, 235, 5, 104, 210, 256, 82, 215, 103, 35, 214, 185, 250, 60, 220, 207, 245, + 213, 10, 208, 163, 255, 164, 173, 206, 70, 171, 113, 243, 120, 183, 157, 233, 169, 20, 159, + 69, 253, 71, 89, 155, 140, 85, 226, 229, 240, 109, 57, 209, 81, 40, 61, 138, 249, 142, 178, + 53, 23, 170, 195, 201, 223, 218, 114, 161, 162, 80, 122, 19, 241, 27, 99, 106, 46, 83, 133, + 145, 189, 179, 228, 65, 67, 160, 244, 38, 225, 54, 198, 212, 92, 166, 9, 33, 121, 101, 199, + 130, 134, 63, 231, 76, 193, 108, 139, 167, 184, 75, 18, 66, 242, 202, 141, 3, 11, 126, 205, + 152, 129, 216, 21, 77, 111, 150, 36, 132, 227, 147, 25, 6, 22, 252, 153, 47, 1, + ], + [ + 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, + 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, + 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, + 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, 2, 95, 15, 70, + 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, 256, 81, 121, 222, + 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, 129, 88, 68, 146, + 253, 67, 227, 117, 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, 64, 213, 223, 184, + 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, 225, 22, 17, 165, + 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, 16, 246, 120, 46, + 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1, 176, 136, 35, 249, 134, 197, 234, + 64, 213, 223, 184, 2, 95, 15, 70, 241, 11, 137, 211, 128, 169, 189, 111, 4, 190, 30, 140, + 225, 22, 17, 165, 256, 81, 121, 222, 8, 123, 60, 23, 193, 44, 34, 73, 255, 162, 242, 187, + 16, 246, 120, 46, 129, 88, 68, 146, 253, 67, 227, 117, 32, 235, 240, 92, 1, + ], + [ + 1, 177, 232, 201, 111, 115, 52, 209, 242, 172, 118, 69, 134, 74, 248, 206, 225, 247, 29, + 250, 46, 175, 135, 251, 223, 150, 79, 105, 81, 202, 31, 90, 253, 63, 100, 224, 70, 54, 49, + 192, 60, 83, 42, 238, 235, 218, 36, 204, 128, 40, 141, 28, 73, 71, 231, 24, 136, 171, 198, + 94, 190, 220, 133, 154, 16, 5, 114, 132, 234, 41, 61, 3, 17, 182, 89, 76, 88, 156, 113, 212, + 2, 97, 207, 145, 222, 230, 104, 161, 227, 87, 236, 138, 11, 148, 239, 155, 193, 237, 58, + 243, 92, 93, 13, 245, 189, 43, 158, 210, 162, 147, 62, 180, 249, 126, 200, 191, 140, 108, + 98, 127, 120, 166, 84, 219, 213, 179, 72, 151, 256, 80, 25, 56, 146, 142, 205, 48, 15, 85, + 139, 188, 123, 183, 9, 51, 32, 10, 228, 7, 211, 82, 122, 6, 34, 107, 178, 152, 176, 55, 226, + 167, 4, 194, 157, 33, 187, 203, 208, 65, 197, 174, 215, 19, 22, 39, 221, 53, 129, 217, 116, + 229, 184, 186, 26, 233, 121, 86, 59, 163, 67, 37, 124, 103, 241, 252, 143, 125, 23, 216, + 196, 254, 240, 75, 168, 181, 169, 101, 144, 45, 255, 160, 50, 112, 35, 27, 153, 96, 30, 170, + 21, 119, 246, 109, 18, 102, 64, 20, 199, 14, 165, 164, 244, 12, 68, 214, 99, 47, 95, 110, + 195, 77, 8, 131, 57, 66, 117, 149, 159, 130, 137, 91, 173, 38, 44, 78, 185, 106, 1, + ], + [ + 1, 178, 73, 144, 189, 232, 176, 231, 255, 158, 111, 226, 136, 50, 162, 52, 4, 198, 35, 62, + 242, 157, 190, 153, 249, 118, 187, 133, 30, 200, 134, 208, 16, 21, 140, 248, 197, 114, 246, + 98, 225, 215, 234, 18, 120, 29, 22, 61, 64, 84, 46, 221, 17, 199, 213, 135, 129, 89, 165, + 72, 223, 116, 88, 244, 256, 79, 184, 113, 68, 25, 81, 26, 2, 99, 146, 31, 121, 207, 95, 205, + 253, 59, 222, 195, 15, 100, 67, 104, 8, 139, 70, 124, 227, 57, 123, 49, 241, 236, 117, 9, + 60, 143, 11, 159, 32, 42, 23, 239, 137, 228, 235, 196, 193, 173, 211, 36, 240, 58, 44, 122, + 128, 168, 92, 185, 34, 141, 169, 13, 1, 178, 73, 144, 189, 232, 176, 231, 255, 158, 111, + 226, 136, 50, 162, 52, 4, 198, 35, 62, 242, 157, 190, 153, 249, 118, 187, 133, 30, 200, 134, + 208, 16, 21, 140, 248, 197, 114, 246, 98, 225, 215, 234, 18, 120, 29, 22, 61, 64, 84, 46, + 221, 17, 199, 213, 135, 129, 89, 165, 72, 223, 116, 88, 244, 256, 79, 184, 113, 68, 25, 81, + 26, 2, 99, 146, 31, 121, 207, 95, 205, 253, 59, 222, 195, 15, 100, 67, 104, 8, 139, 70, 124, + 227, 57, 123, 49, 241, 236, 117, 9, 60, 143, 11, 159, 32, 42, 23, 239, 137, 228, 235, 196, + 193, 173, 211, 36, 240, 58, 44, 122, 128, 168, 92, 185, 34, 141, 169, 13, 1, + ], + [ + 1, 179, 173, 127, 117, 126, 195, 210, 68, 93, 199, 155, 246, 87, 153, 145, 255, 156, 168, 3, + 23, 5, 124, 94, 121, 71, 116, 204, 22, 83, 208, 224, 4, 202, 178, 251, 211, 247, 9, 69, 15, + 115, 25, 106, 213, 91, 98, 66, 249, 110, 158, 12, 92, 20, 239, 119, 227, 27, 207, 45, 88, + 75, 61, 125, 16, 37, 198, 233, 73, 217, 36, 19, 60, 203, 100, 167, 81, 107, 135, 7, 225, + 183, 118, 48, 111, 80, 185, 219, 137, 108, 57, 180, 95, 43, 244, 243, 64, 148, 21, 161, 35, + 97, 144, 76, 240, 41, 143, 154, 67, 171, 26, 28, 129, 218, 215, 192, 187, 63, 226, 105, 34, + 175, 228, 206, 123, 172, 205, 201, 256, 78, 84, 130, 140, 131, 62, 47, 189, 164, 58, 102, + 11, 170, 104, 112, 2, 101, 89, 254, 234, 252, 133, 163, 136, 186, 141, 53, 235, 174, 49, 33, + 253, 55, 79, 6, 46, 10, 248, 188, 242, 142, 232, 151, 44, 166, 159, 191, 8, 147, 99, 245, + 165, 237, 18, 138, 30, 230, 50, 212, 169, 182, 196, 132, 241, 220, 59, 24, 184, 40, 221, + 238, 197, 54, 157, 90, 176, 150, 122, 250, 32, 74, 139, 209, 146, 177, 72, 38, 120, 149, + 200, 77, 162, 214, 13, 14, 193, 109, 236, 96, 222, 160, 113, 181, 17, 216, 114, 103, 190, + 86, 231, 229, 128, 39, 42, 65, 70, 194, 31, 152, 223, 82, 29, 51, 134, 85, 52, 56, 1, + ], + [ + 1, 180, 18, 156, 67, 238, 178, 172, 120, 12, 104, 216, 73, 33, 29, 80, 8, 155, 144, 220, 22, + 105, 139, 91, 189, 96, 61, 186, 70, 7, 232, 126, 64, 212, 124, 218, 176, 69, 84, 214, 227, + 254, 231, 203, 46, 56, 57, 237, 255, 154, 221, 202, 123, 38, 158, 170, 17, 233, 49, 82, 111, + 191, 199, 97, 241, 204, 226, 74, 213, 47, 236, 75, 136, 65, 135, 142, 117, 243, 50, 5, 129, + 90, 9, 78, 162, 119, 89, 86, 60, 6, 52, 108, 165, 145, 143, 40, 4, 206, 72, 110, 11, 181, + 198, 174, 223, 48, 159, 93, 35, 132, 116, 63, 32, 106, 62, 109, 88, 163, 42, 107, 242, 127, + 244, 230, 23, 28, 157, 247, 256, 77, 239, 101, 190, 19, 79, 85, 137, 245, 153, 41, 184, 224, + 228, 177, 249, 102, 113, 37, 235, 152, 118, 166, 68, 161, 196, 71, 187, 250, 25, 131, 193, + 45, 133, 39, 81, 188, 173, 43, 30, 3, 26, 54, 211, 201, 200, 20, 2, 103, 36, 55, 134, 219, + 99, 87, 240, 24, 208, 175, 146, 66, 58, 160, 16, 53, 31, 183, 44, 210, 21, 182, 121, 192, + 122, 115, 140, 14, 207, 252, 128, 167, 248, 179, 95, 138, 168, 171, 197, 251, 205, 149, 92, + 112, 114, 217, 253, 51, 185, 147, 246, 76, 59, 83, 34, 209, 98, 164, 222, 125, 141, 194, + 225, 151, 195, 148, 169, 94, 215, 150, 15, 130, 13, 27, 234, 229, 100, 10, 1, + ], + [ + 1, 181, 122, 237, 235, 130, 143, 183, 227, 224, 195, 86, 146, 212, 79, 164, 129, 219, 61, + 247, 246, 65, 200, 220, 242, 112, 226, 43, 73, 106, 168, 82, 193, 238, 159, 252, 123, 161, + 100, 110, 121, 56, 113, 150, 165, 53, 84, 41, 225, 119, 208, 126, 190, 209, 50, 55, 189, 28, + 185, 75, 211, 155, 42, 149, 241, 188, 104, 63, 95, 233, 25, 156, 223, 14, 221, 166, 234, + 206, 21, 203, 249, 94, 52, 160, 176, 245, 141, 78, 240, 7, 239, 83, 117, 103, 139, 230, 253, + 47, 26, 80, 88, 251, 199, 39, 120, 132, 248, 170, 187, 180, 198, 115, 255, 152, 13, 40, 44, + 254, 228, 148, 60, 66, 124, 85, 222, 90, 99, 186, 256, 76, 135, 20, 22, 127, 114, 74, 30, + 33, 62, 171, 111, 45, 178, 93, 128, 38, 196, 10, 11, 192, 57, 37, 15, 145, 31, 214, 184, + 151, 89, 175, 64, 19, 98, 5, 134, 96, 157, 147, 136, 201, 144, 107, 92, 204, 173, 216, 32, + 138, 49, 131, 67, 48, 207, 202, 68, 229, 72, 182, 46, 102, 215, 108, 16, 69, 153, 194, 162, + 24, 232, 101, 34, 243, 36, 91, 23, 51, 236, 54, 8, 163, 205, 97, 81, 12, 116, 179, 17, 250, + 18, 174, 140, 154, 118, 27, 4, 210, 231, 177, 169, 6, 58, 218, 137, 125, 9, 87, 70, 77, 59, + 142, 2, 105, 244, 217, 213, 3, 29, 109, 197, 191, 133, 172, 35, 167, 158, 71, 1, + ], + [ + 1, 182, 228, 119, 70, 147, 26, 106, 17, 10, 21, 224, 162, 186, 185, 3, 32, 170, 100, 210, + 184, 78, 61, 51, 30, 63, 158, 229, 44, 41, 9, 96, 253, 43, 116, 38, 234, 183, 153, 90, 189, + 217, 173, 132, 123, 27, 31, 245, 129, 91, 114, 188, 35, 202, 13, 53, 137, 5, 139, 112, 81, + 93, 221, 130, 16, 85, 50, 105, 92, 39, 159, 154, 15, 160, 79, 243, 22, 149, 133, 48, 255, + 150, 58, 19, 117, 220, 205, 45, 223, 237, 215, 66, 190, 142, 144, 251, 193, 174, 57, 94, + 146, 101, 135, 155, 197, 131, 198, 56, 169, 175, 239, 65, 8, 171, 25, 181, 46, 148, 208, 77, + 136, 80, 168, 250, 11, 203, 195, 24, 256, 75, 29, 138, 187, 110, 231, 151, 240, 247, 236, + 33, 95, 71, 72, 254, 225, 87, 157, 47, 73, 179, 196, 206, 227, 194, 99, 28, 213, 216, 248, + 161, 4, 214, 141, 219, 23, 74, 104, 167, 68, 40, 84, 125, 134, 230, 226, 12, 128, 166, 143, + 69, 222, 55, 244, 204, 120, 252, 118, 145, 176, 164, 36, 127, 241, 172, 207, 152, 165, 218, + 98, 103, 242, 97, 178, 14, 235, 108, 124, 209, 2, 107, 199, 238, 140, 37, 52, 212, 34, 20, + 42, 191, 67, 115, 113, 6, 64, 83, 200, 163, 111, 156, 122, 102, 60, 126, 59, 201, 88, 82, + 18, 192, 249, 86, 232, 76, 211, 109, 49, 180, 121, 177, 89, 7, 246, 54, 62, 233, 1, + ], + [ + 1, 183, 79, 65, 73, 252, 113, 119, 189, 149, 25, 206, 176, 83, 26, 132, 255, 148, 99, 127, + 111, 10, 31, 19, 136, 216, 207, 102, 162, 91, 205, 250, 4, 218, 59, 3, 35, 237, 195, 219, + 242, 82, 100, 53, 190, 75, 104, 14, 249, 78, 139, 251, 187, 40, 124, 76, 30, 93, 57, 151, + 134, 107, 49, 229, 16, 101, 236, 12, 140, 177, 9, 105, 197, 71, 143, 212, 246, 43, 159, 56, + 225, 55, 42, 233, 234, 160, 239, 47, 120, 115, 228, 90, 22, 171, 196, 145, 64, 147, 173, 48, + 46, 194, 36, 163, 17, 27, 58, 77, 213, 172, 122, 224, 129, 220, 168, 161, 165, 126, 185, + 188, 223, 203, 141, 103, 88, 170, 13, 66, 256, 74, 178, 192, 184, 5, 144, 138, 68, 108, 232, + 51, 81, 174, 231, 125, 2, 109, 158, 130, 146, 247, 226, 238, 121, 41, 50, 155, 95, 166, 52, + 7, 253, 39, 198, 254, 222, 20, 62, 38, 15, 175, 157, 204, 67, 182, 153, 243, 8, 179, 118, 6, + 70, 217, 133, 181, 227, 164, 200, 106, 123, 150, 208, 28, 241, 156, 21, 245, 117, 80, 248, + 152, 60, 186, 114, 45, 11, 214, 98, 201, 32, 202, 215, 24, 23, 97, 18, 210, 137, 142, 29, + 167, 235, 86, 61, 112, 193, 110, 84, 209, 211, 63, 221, 94, 240, 230, 199, 180, 44, 85, 135, + 33, 128, 37, 89, 96, 92, 131, 72, 69, 34, 54, 116, 154, 169, 87, 244, 191, 1, + ], + [ + 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, + 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, + 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, + 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, 70, 30, 123, 16, + 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, 73, 68, 176, 2, + 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, 234, 137, 22, 193, + 46, 240, 213, 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, 222, 242, 67, 249, + 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, 92, 223, 169, 256, + 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, 140, 60, 246, 32, + 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1, 184, 189, 81, 255, 146, 136, 95, 4, + 222, 242, 67, 249, 70, 30, 123, 16, 117, 197, 11, 225, 23, 120, 235, 64, 211, 17, 44, 129, + 92, 223, 169, 256, 73, 68, 176, 2, 111, 121, 162, 253, 35, 15, 190, 8, 187, 227, 134, 241, + 140, 60, 246, 32, 234, 137, 22, 193, 46, 240, 213, 128, 165, 34, 88, 1, + ], + [ + 1, 185, 44, 173, 137, 159, 117, 57, 8, 195, 95, 99, 68, 244, 165, 199, 64, 18, 246, 21, 30, + 153, 35, 50, 255, 144, 169, 168, 240, 196, 23, 143, 241, 124, 67, 59, 121, 26, 184, 116, + 129, 221, 22, 215, 197, 208, 187, 157, 4, 226, 176, 178, 34, 122, 211, 228, 32, 9, 123, 139, + 15, 205, 146, 25, 256, 72, 213, 84, 120, 98, 140, 200, 249, 62, 162, 158, 189, 13, 92, 58, + 193, 239, 11, 236, 227, 104, 222, 207, 2, 113, 88, 89, 17, 61, 234, 114, 16, 133, 190, 198, + 136, 231, 73, 141, 128, 36, 235, 42, 60, 49, 70, 100, 253, 31, 81, 79, 223, 135, 46, 29, + 225, 248, 134, 118, 242, 52, 111, 232, 1, 185, 44, 173, 137, 159, 117, 57, 8, 195, 95, 99, + 68, 244, 165, 199, 64, 18, 246, 21, 30, 153, 35, 50, 255, 144, 169, 168, 240, 196, 23, 143, + 241, 124, 67, 59, 121, 26, 184, 116, 129, 221, 22, 215, 197, 208, 187, 157, 4, 226, 176, + 178, 34, 122, 211, 228, 32, 9, 123, 139, 15, 205, 146, 25, 256, 72, 213, 84, 120, 98, 140, + 200, 249, 62, 162, 158, 189, 13, 92, 58, 193, 239, 11, 236, 227, 104, 222, 207, 2, 113, 88, + 89, 17, 61, 234, 114, 16, 133, 190, 198, 136, 231, 73, 141, 128, 36, 235, 42, 60, 49, 70, + 100, 253, 31, 81, 79, 223, 135, 46, 29, 225, 248, 134, 118, 242, 52, 111, 232, 1, + ], + [ + 1, 186, 158, 90, 35, 85, 133, 66, 197, 148, 29, 254, 213, 40, 244, 152, 2, 115, 59, 180, 70, + 170, 9, 132, 137, 39, 58, 251, 169, 80, 231, 47, 4, 230, 118, 103, 140, 83, 18, 7, 17, 78, + 116, 245, 81, 160, 205, 94, 8, 203, 236, 206, 23, 166, 36, 14, 34, 156, 232, 233, 162, 63, + 153, 188, 16, 149, 215, 155, 46, 75, 72, 28, 68, 55, 207, 209, 67, 126, 49, 119, 32, 41, + 173, 53, 92, 150, 144, 56, 136, 110, 157, 161, 134, 252, 98, 238, 64, 82, 89, 106, 184, 43, + 31, 112, 15, 220, 57, 65, 11, 247, 196, 219, 128, 164, 178, 212, 111, 86, 62, 224, 30, 183, + 114, 130, 22, 237, 135, 181, 256, 71, 99, 167, 222, 172, 124, 191, 60, 109, 228, 3, 44, 217, + 13, 105, 255, 142, 198, 77, 187, 87, 248, 125, 120, 218, 199, 6, 88, 177, 26, 210, 253, 27, + 139, 154, 117, 174, 239, 250, 240, 179, 141, 12, 176, 97, 52, 163, 249, 54, 21, 51, 234, 91, + 221, 243, 223, 101, 25, 24, 95, 194, 104, 69, 241, 108, 42, 102, 211, 182, 185, 229, 189, + 202, 50, 48, 190, 131, 208, 138, 225, 216, 84, 204, 165, 107, 113, 201, 121, 147, 100, 96, + 123, 5, 159, 19, 193, 175, 168, 151, 73, 214, 226, 145, 242, 37, 200, 192, 246, 10, 61, 38, + 129, 93, 79, 45, 146, 171, 195, 33, 227, 74, 143, 127, 235, 20, 122, 76, 1, + ], + [ + 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, + 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, + 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, + 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, 222, 137, 176, + 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, 256, 70, 240, 162, + 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, 2, 117, 34, 190, 64, + 146, 60, 169, 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, 23, 189, 134, 129, + 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, 211, 136, 246, + 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, 92, 242, 22, + 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1, 187, 17, 95, 32, 73, 30, 213, 253, + 23, 189, 134, 129, 222, 137, 176, 16, 165, 15, 235, 255, 140, 223, 67, 193, 111, 197, 88, 8, + 211, 136, 246, 256, 70, 240, 162, 225, 184, 227, 44, 4, 234, 68, 123, 128, 35, 120, 81, 241, + 92, 242, 22, 2, 117, 34, 190, 64, 146, 60, 169, 249, 46, 121, 11, 1, + ], + [ + 1, 188, 135, 194, 235, 233, 114, 101, 227, 14, 62, 91, 146, 206, 178, 54, 129, 94, 196, 97, + 246, 245, 57, 179, 242, 7, 31, 174, 73, 103, 89, 27, 193, 47, 98, 177, 123, 251, 157, 218, + 121, 132, 144, 87, 165, 180, 173, 142, 225, 152, 49, 217, 190, 254, 207, 109, 189, 66, 72, + 172, 211, 90, 215, 71, 241, 76, 153, 237, 95, 127, 232, 183, 223, 33, 36, 86, 234, 45, 236, + 164, 249, 38, 205, 247, 176, 192, 116, 220, 240, 145, 18, 43, 117, 151, 118, 82, 253, 19, + 231, 252, 88, 96, 58, 110, 120, 201, 9, 150, 187, 204, 59, 41, 255, 138, 244, 126, 44, 48, + 29, 55, 60, 229, 133, 75, 222, 102, 158, 149, 256, 69, 122, 63, 22, 24, 143, 156, 30, 243, + 195, 166, 111, 51, 79, 203, 128, 163, 61, 160, 11, 12, 200, 78, 15, 250, 226, 83, 184, 154, + 168, 230, 64, 210, 159, 80, 134, 6, 100, 39, 136, 125, 113, 170, 92, 77, 84, 115, 32, 105, + 208, 40, 67, 3, 50, 148, 68, 191, 185, 85, 46, 167, 42, 186, 16, 181, 104, 20, 162, 130, 25, + 74, 34, 224, 221, 171, 23, 212, 21, 93, 8, 219, 52, 10, 81, 65, 141, 37, 17, 112, 239, 214, + 140, 106, 139, 175, 4, 238, 26, 5, 169, 161, 199, 147, 137, 56, 248, 107, 70, 53, 198, 216, + 2, 119, 13, 131, 213, 209, 228, 202, 197, 28, 124, 182, 35, 155, 99, 108, 1, + ], + [ + 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, + 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, + 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, + 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, + 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, + 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, + 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, + 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, + 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, + 241, 60, 32, 137, 193, 240, 128, 34, 1, 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, + 64, 17, 129, 223, 256, 68, 2, 121, 253, 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, + 189, 255, 136, 4, 242, 249, 30, 16, 197, 225, 120, 64, 17, 129, 223, 256, 68, 2, 121, 253, + 15, 8, 227, 241, 60, 32, 137, 193, 240, 128, 34, 1, + ], + [ + 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, + 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, + 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, + 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, 134, 17, 146, + 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, 67, 137, 73, + 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, 162, 197, 165, + 253, 11, 34, 35, 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, 227, 211, 255, + 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, 242, 234, 256, + 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, 121, 117, 128, + 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1, 190, 120, 184, 8, 235, 189, 187, 64, 81, + 227, 211, 255, 134, 17, 146, 241, 44, 136, 140, 129, 95, 60, 92, 4, 246, 223, 222, 32, 169, + 242, 234, 256, 67, 137, 73, 249, 22, 68, 70, 193, 176, 30, 46, 2, 123, 240, 111, 16, 213, + 121, 117, 128, 162, 197, 165, 253, 11, 34, 35, 225, 88, 15, 23, 1, + ], + [ + 1, 191, 244, 87, 169, 154, 116, 54, 34, 69, 72, 131, 92, 96, 89, 37, 128, 33, 135, 85, 44, + 180, 199, 230, 240, 94, 221, 63, 211, 209, 84, 110, 193, 112, 61, 86, 235, 167, 29, 142, + 137, 210, 18, 97, 23, 24, 215, 202, 32, 201, 98, 214, 11, 45, 114, 186, 60, 152, 248, 80, + 117, 245, 21, 156, 241, 28, 208, 150, 123, 106, 200, 164, 227, 181, 133, 217, 70, 6, 118, + 179, 8, 243, 153, 182, 67, 204, 157, 175, 15, 38, 62, 20, 222, 254, 198, 39, 253, 7, 52, + 166, 95, 155, 50, 41, 121, 238, 226, 247, 146, 130, 158, 109, 2, 125, 231, 174, 81, 51, 232, + 108, 68, 138, 144, 5, 184, 192, 178, 74, 256, 66, 13, 170, 88, 103, 141, 203, 223, 188, 185, + 126, 165, 161, 168, 220, 129, 224, 122, 172, 213, 77, 58, 27, 17, 163, 36, 194, 46, 48, 173, + 147, 64, 145, 196, 171, 22, 90, 228, 115, 120, 47, 239, 160, 234, 233, 42, 55, 225, 56, 159, + 43, 246, 212, 143, 71, 197, 105, 9, 177, 140, 12, 236, 101, 16, 229, 49, 107, 134, 151, 57, + 93, 30, 76, 124, 40, 187, 251, 139, 78, 249, 14, 104, 75, 190, 53, 100, 82, 242, 219, 195, + 237, 35, 3, 59, 218, 4, 250, 205, 91, 162, 102, 207, 216, 136, 19, 31, 10, 111, 127, 99, + 148, 255, 132, 26, 83, 176, 206, 25, 149, 189, 119, 113, 252, 73, 65, 79, 183, 1, + ], + [ + 1, 192, 113, 108, 176, 125, 99, 247, 136, 155, 205, 39, 35, 38, 100, 182, 249, 6, 124, 164, + 134, 28, 236, 80, 197, 45, 159, 202, 234, 210, 228, 86, 64, 209, 36, 230, 213, 33, 168, 131, + 223, 154, 13, 183, 184, 119, 232, 83, 2, 127, 226, 216, 95, 250, 198, 237, 15, 53, 153, 78, + 70, 76, 200, 107, 241, 12, 248, 71, 11, 56, 215, 160, 137, 90, 61, 147, 211, 163, 199, 172, + 128, 161, 72, 203, 169, 66, 79, 5, 189, 51, 26, 109, 111, 238, 207, 166, 4, 254, 195, 175, + 190, 243, 139, 217, 30, 106, 49, 156, 140, 152, 143, 214, 225, 24, 239, 142, 22, 112, 173, + 63, 17, 180, 122, 37, 165, 69, 141, 87, 256, 65, 144, 149, 81, 132, 158, 10, 121, 102, 52, + 218, 222, 219, 157, 75, 8, 251, 133, 93, 123, 229, 21, 177, 60, 212, 98, 55, 23, 47, 29, + 171, 193, 48, 221, 27, 44, 224, 89, 126, 34, 103, 244, 74, 73, 138, 25, 174, 255, 130, 31, + 41, 162, 7, 59, 20, 242, 204, 104, 179, 187, 181, 57, 150, 16, 245, 9, 186, 246, 201, 42, + 97, 120, 167, 196, 110, 46, 94, 58, 85, 129, 96, 185, 54, 88, 191, 178, 252, 68, 206, 231, + 148, 146, 19, 50, 91, 253, 3, 62, 82, 67, 14, 118, 40, 227, 151, 208, 101, 117, 105, 114, + 43, 32, 233, 18, 115, 235, 145, 84, 194, 240, 77, 135, 220, 92, 188, 116, 170, 1, + ], + [ + 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, + 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, + 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, + 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, + 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, + 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, + 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, + 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, + 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, + 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, + 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, + 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, 193, 241, 253, 256, 64, 16, 4, 1, + ], + [ + 1, 194, 114, 14, 146, 54, 196, 245, 242, 174, 89, 47, 123, 218, 144, 180, 225, 217, 207, 66, + 211, 71, 153, 127, 223, 86, 236, 38, 176, 220, 18, 151, 253, 252, 58, 201, 187, 41, 244, 48, + 60, 75, 158, 69, 22, 156, 195, 51, 128, 160, 200, 250, 184, 230, 159, 6, 136, 170, 84, 105, + 67, 148, 185, 167, 16, 20, 25, 224, 23, 93, 52, 65, 17, 214, 139, 238, 169, 147, 248, 53, 2, + 131, 228, 28, 35, 108, 135, 233, 227, 91, 178, 94, 246, 179, 31, 103, 193, 177, 157, 132, + 165, 142, 49, 254, 189, 172, 215, 76, 95, 183, 36, 45, 249, 247, 116, 145, 117, 82, 231, 96, + 120, 150, 59, 138, 44, 55, 133, 102, 256, 63, 143, 243, 111, 203, 61, 12, 15, 83, 168, 210, + 134, 39, 113, 77, 32, 40, 50, 191, 46, 186, 104, 130, 34, 171, 21, 219, 81, 37, 239, 106, 4, + 5, 199, 56, 70, 216, 13, 209, 197, 182, 99, 188, 235, 101, 62, 206, 129, 97, 57, 7, 73, 27, + 98, 251, 121, 87, 173, 152, 190, 109, 72, 90, 241, 237, 232, 33, 234, 164, 205, 192, 240, + 43, 118, 19, 88, 110, 9, 204, 255, 126, 29, 229, 222, 149, 122, 24, 30, 166, 79, 163, 11, + 78, 226, 154, 64, 80, 100, 125, 92, 115, 208, 3, 68, 85, 42, 181, 162, 74, 221, 212, 8, 10, + 141, 112, 140, 175, 26, 161, 137, 107, 198, 119, 213, 202, 124, 155, 1, + ], + [ + 1, 195, 246, 168, 121, 208, 211, 25, 249, 239, 88, 198, 60, 135, 111, 57, 64, 144, 67, 215, + 34, 205, 140, 58, 2, 133, 235, 79, 242, 159, 165, 50, 241, 221, 176, 139, 120, 13, 222, 114, + 128, 31, 134, 173, 68, 153, 23, 116, 4, 9, 213, 158, 227, 61, 73, 100, 225, 185, 95, 21, + 240, 26, 187, 228, 256, 62, 11, 89, 136, 49, 46, 232, 8, 18, 169, 59, 197, 122, 146, 200, + 193, 113, 190, 42, 223, 52, 117, 199, 255, 124, 22, 178, 15, 98, 92, 207, 16, 36, 81, 118, + 137, 244, 35, 143, 129, 226, 123, 84, 189, 104, 234, 141, 253, 248, 44, 99, 30, 196, 184, + 157, 32, 72, 162, 236, 17, 231, 70, 29, 1, 195, 246, 168, 121, 208, 211, 25, 249, 239, 88, + 198, 60, 135, 111, 57, 64, 144, 67, 215, 34, 205, 140, 58, 2, 133, 235, 79, 242, 159, 165, + 50, 241, 221, 176, 139, 120, 13, 222, 114, 128, 31, 134, 173, 68, 153, 23, 116, 4, 9, 213, + 158, 227, 61, 73, 100, 225, 185, 95, 21, 240, 26, 187, 228, 256, 62, 11, 89, 136, 49, 46, + 232, 8, 18, 169, 59, 197, 122, 146, 200, 193, 113, 190, 42, 223, 52, 117, 199, 255, 124, 22, + 178, 15, 98, 92, 207, 16, 36, 81, 118, 137, 244, 35, 143, 129, 226, 123, 84, 189, 104, 234, + 141, 253, 248, 44, 99, 30, 196, 184, 157, 32, 72, 162, 236, 17, 231, 70, 29, 1, + ], + [ + 1, 196, 123, 207, 223, 18, 187, 158, 128, 159, 67, 25, 17, 248, 35, 178, 193, 49, 95, 116, + 120, 133, 111, 168, 32, 104, 81, 199, 197, 62, 73, 173, 241, 205, 88, 29, 30, 226, 92, 42, + 8, 26, 213, 114, 242, 144, 211, 236, 253, 244, 22, 200, 136, 185, 23, 139, 2, 135, 246, 157, + 189, 36, 117, 59, 256, 61, 134, 50, 34, 239, 70, 99, 129, 98, 190, 232, 240, 9, 222, 79, 64, + 208, 162, 141, 137, 124, 146, 89, 225, 153, 176, 58, 60, 195, 184, 84, 16, 52, 169, 228, + 227, 31, 165, 215, 249, 231, 44, 143, 15, 113, 46, 21, 4, 13, 235, 57, 121, 72, 234, 118, + 255, 122, 11, 100, 68, 221, 140, 198, 1, 196, 123, 207, 223, 18, 187, 158, 128, 159, 67, 25, + 17, 248, 35, 178, 193, 49, 95, 116, 120, 133, 111, 168, 32, 104, 81, 199, 197, 62, 73, 173, + 241, 205, 88, 29, 30, 226, 92, 42, 8, 26, 213, 114, 242, 144, 211, 236, 253, 244, 22, 200, + 136, 185, 23, 139, 2, 135, 246, 157, 189, 36, 117, 59, 256, 61, 134, 50, 34, 239, 70, 99, + 129, 98, 190, 232, 240, 9, 222, 79, 64, 208, 162, 141, 137, 124, 146, 89, 225, 153, 176, 58, + 60, 195, 184, 84, 16, 52, 169, 228, 227, 31, 165, 215, 249, 231, 44, 143, 15, 113, 46, 21, + 4, 13, 235, 57, 121, 72, 234, 118, 255, 122, 11, 100, 68, 221, 140, 198, 1, + ], + [ + 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, + 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, + 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, + 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, + 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, + 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, + 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, + 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, + 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, + 225, 121, 193, 242, 129, 227, 1, 197, 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, + 30, 256, 60, 255, 120, 253, 240, 249, 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, 197, + 2, 137, 4, 17, 8, 34, 16, 68, 32, 136, 64, 15, 128, 30, 256, 60, 255, 120, 253, 240, 249, + 223, 241, 189, 225, 121, 193, 242, 129, 227, 1, + ], + [ + 1, 198, 140, 221, 68, 100, 11, 122, 255, 118, 234, 72, 121, 57, 235, 13, 4, 21, 46, 113, 15, + 143, 44, 231, 249, 215, 165, 31, 227, 228, 169, 52, 16, 84, 184, 195, 60, 58, 176, 153, 225, + 89, 146, 124, 137, 141, 162, 208, 64, 79, 222, 9, 240, 232, 190, 98, 129, 99, 70, 239, 34, + 50, 134, 61, 256, 59, 117, 36, 189, 157, 246, 135, 2, 139, 23, 185, 136, 200, 22, 244, 253, + 236, 211, 144, 242, 114, 213, 26, 8, 42, 92, 226, 30, 29, 88, 205, 241, 173, 73, 62, 197, + 199, 81, 104, 32, 168, 111, 133, 120, 116, 95, 49, 193, 178, 35, 248, 17, 25, 67, 159, 128, + 158, 187, 18, 223, 207, 123, 196, 1, 198, 140, 221, 68, 100, 11, 122, 255, 118, 234, 72, + 121, 57, 235, 13, 4, 21, 46, 113, 15, 143, 44, 231, 249, 215, 165, 31, 227, 228, 169, 52, + 16, 84, 184, 195, 60, 58, 176, 153, 225, 89, 146, 124, 137, 141, 162, 208, 64, 79, 222, 9, + 240, 232, 190, 98, 129, 99, 70, 239, 34, 50, 134, 61, 256, 59, 117, 36, 189, 157, 246, 135, + 2, 139, 23, 185, 136, 200, 22, 244, 253, 236, 211, 144, 242, 114, 213, 26, 8, 42, 92, 226, + 30, 29, 88, 205, 241, 173, 73, 62, 197, 199, 81, 104, 32, 168, 111, 133, 120, 116, 95, 49, + 193, 178, 35, 248, 17, 25, 67, 159, 128, 158, 187, 18, 223, 207, 123, 196, 1, + ], + [ + 1, 199, 23, 208, 15, 158, 88, 36, 225, 57, 35, 26, 34, 84, 11, 133, 253, 232, 165, 196, 197, + 139, 162, 113, 128, 29, 117, 153, 121, 178, 213, 239, 16, 100, 111, 244, 240, 215, 123, 62, + 2, 141, 46, 159, 30, 59, 176, 72, 193, 114, 70, 52, 68, 168, 22, 9, 249, 207, 73, 135, 137, + 21, 67, 226, 256, 58, 234, 49, 242, 99, 169, 221, 32, 200, 222, 231, 223, 173, 246, 124, 4, + 25, 92, 61, 60, 118, 95, 144, 129, 228, 140, 104, 136, 79, 44, 18, 241, 157, 146, 13, 17, + 42, 134, 195, 255, 116, 211, 98, 227, 198, 81, 185, 64, 143, 187, 205, 189, 89, 235, 248, 8, + 50, 184, 122, 120, 236, 190, 31, 1, 199, 23, 208, 15, 158, 88, 36, 225, 57, 35, 26, 34, 84, + 11, 133, 253, 232, 165, 196, 197, 139, 162, 113, 128, 29, 117, 153, 121, 178, 213, 239, 16, + 100, 111, 244, 240, 215, 123, 62, 2, 141, 46, 159, 30, 59, 176, 72, 193, 114, 70, 52, 68, + 168, 22, 9, 249, 207, 73, 135, 137, 21, 67, 226, 256, 58, 234, 49, 242, 99, 169, 221, 32, + 200, 222, 231, 223, 173, 246, 124, 4, 25, 92, 61, 60, 118, 95, 144, 129, 228, 140, 104, 136, + 79, 44, 18, 241, 157, 146, 13, 17, 42, 134, 195, 255, 116, 211, 98, 227, 198, 81, 185, 64, + 143, 187, 205, 189, 89, 235, 248, 8, 50, 184, 122, 120, 236, 190, 31, 1, + ], + [ + 1, 200, 165, 104, 240, 198, 22, 31, 32, 232, 140, 244, 227, 168, 190, 221, 253, 228, 111, + 98, 68, 236, 169, 133, 129, 100, 211, 52, 120, 99, 11, 144, 16, 116, 70, 122, 242, 84, 95, + 239, 255, 114, 184, 49, 34, 118, 213, 195, 193, 50, 234, 26, 60, 178, 134, 72, 8, 58, 35, + 61, 121, 42, 176, 248, 256, 57, 92, 153, 17, 59, 235, 226, 225, 25, 117, 13, 30, 89, 67, 36, + 4, 29, 146, 159, 189, 21, 88, 124, 128, 157, 46, 205, 137, 158, 246, 113, 241, 141, 187, + 135, 15, 173, 162, 18, 2, 143, 73, 208, 223, 139, 44, 62, 64, 207, 23, 231, 197, 79, 123, + 185, 249, 199, 222, 196, 136, 215, 81, 9, 1, 200, 165, 104, 240, 198, 22, 31, 32, 232, 140, + 244, 227, 168, 190, 221, 253, 228, 111, 98, 68, 236, 169, 133, 129, 100, 211, 52, 120, 99, + 11, 144, 16, 116, 70, 122, 242, 84, 95, 239, 255, 114, 184, 49, 34, 118, 213, 195, 193, 50, + 234, 26, 60, 178, 134, 72, 8, 58, 35, 61, 121, 42, 176, 248, 256, 57, 92, 153, 17, 59, 235, + 226, 225, 25, 117, 13, 30, 89, 67, 36, 4, 29, 146, 159, 189, 21, 88, 124, 128, 157, 46, 205, + 137, 158, 246, 113, 241, 141, 187, 135, 15, 173, 162, 18, 2, 143, 73, 208, 223, 139, 44, 62, + 64, 207, 23, 231, 197, 79, 123, 185, 249, 199, 222, 196, 136, 215, 81, 9, 1, + ], + [ + 1, 201, 52, 172, 134, 206, 29, 175, 223, 105, 31, 63, 70, 192, 42, 218, 128, 28, 231, 171, + 190, 154, 114, 41, 17, 76, 113, 97, 222, 161, 236, 148, 193, 243, 13, 43, 162, 180, 200, + 108, 120, 219, 72, 80, 146, 48, 139, 183, 32, 7, 122, 107, 176, 167, 157, 203, 197, 19, 221, + 217, 184, 233, 59, 37, 241, 125, 196, 75, 169, 45, 50, 27, 30, 119, 18, 20, 165, 12, 99, + 110, 8, 66, 159, 91, 44, 106, 232, 115, 242, 69, 248, 247, 46, 251, 79, 202, 253, 224, 49, + 83, 235, 204, 141, 71, 136, 94, 133, 5, 234, 3, 89, 156, 2, 145, 104, 87, 11, 155, 58, 93, + 189, 210, 62, 126, 140, 127, 84, 179, 256, 56, 205, 85, 123, 51, 228, 82, 34, 152, 226, 194, + 187, 65, 215, 39, 129, 229, 26, 86, 67, 103, 143, 216, 240, 181, 144, 160, 35, 96, 21, 109, + 64, 14, 244, 214, 95, 77, 57, 149, 137, 38, 185, 177, 111, 209, 118, 74, 225, 250, 135, 150, + 81, 90, 100, 54, 60, 238, 36, 40, 73, 24, 198, 220, 16, 132, 61, 182, 88, 212, 207, 230, + 227, 138, 239, 237, 92, 245, 158, 147, 249, 191, 98, 166, 213, 151, 25, 142, 15, 188, 9, 10, + 211, 6, 178, 55, 4, 33, 208, 174, 22, 53, 116, 186, 121, 163, 124, 252, 23, 254, 168, 101, + 255, 112, 153, 170, 246, 102, 199, 164, 68, 47, 195, 131, 117, 130, 173, 78, 1, + ], + [ + 1, 202, 198, 161, 140, 10, 221, 181, 68, 115, 100, 154, 11, 166, 122, 229, 255, 110, 118, + 192, 234, 237, 72, 152, 121, 27, 57, 206, 235, 182, 13, 56, 4, 37, 21, 130, 46, 40, 113, + 210, 15, 203, 143, 102, 44, 150, 231, 145, 249, 183, 215, 254, 165, 177, 31, 94, 227, 108, + 228, 53, 169, 214, 52, 224, 16, 148, 84, 6, 184, 160, 195, 69, 60, 41, 58, 151, 176, 86, + 153, 66, 225, 218, 89, 245, 146, 194, 124, 119, 137, 175, 141, 212, 162, 85, 208, 125, 64, + 78, 79, 24, 222, 126, 9, 19, 240, 164, 232, 90, 190, 87, 98, 7, 129, 101, 99, 209, 70, 5, + 239, 219, 34, 186, 50, 77, 134, 83, 61, 243, 256, 55, 59, 96, 117, 247, 36, 76, 189, 142, + 157, 103, 246, 91, 135, 28, 2, 147, 139, 65, 23, 20, 185, 105, 136, 230, 200, 51, 22, 75, + 244, 201, 253, 220, 236, 127, 211, 217, 144, 47, 242, 54, 114, 155, 213, 107, 26, 112, 8, + 74, 42, 3, 92, 80, 226, 163, 30, 149, 29, 204, 88, 43, 205, 33, 241, 109, 173, 251, 73, 97, + 62, 188, 197, 216, 199, 106, 81, 171, 104, 191, 32, 39, 168, 12, 111, 63, 133, 138, 120, 82, + 116, 45, 95, 172, 49, 132, 193, 179, 178, 233, 35, 131, 248, 238, 17, 93, 25, 167, 67, 170, + 159, 250, 128, 156, 158, 48, 187, 252, 18, 38, 223, 71, 207, 180, 123, 174, 196, 14, 1, + ], + [ + 1, 203, 89, 77, 211, 171, 18, 56, 60, 101, 200, 251, 67, 237, 52, 19, 2, 149, 178, 154, 165, + 85, 36, 112, 120, 202, 143, 245, 134, 217, 104, 38, 4, 41, 99, 51, 73, 170, 72, 224, 240, + 147, 29, 233, 11, 177, 208, 76, 8, 82, 198, 102, 146, 83, 144, 191, 223, 37, 58, 209, 22, + 97, 159, 152, 16, 164, 139, 204, 35, 166, 31, 125, 189, 74, 116, 161, 44, 194, 61, 47, 32, + 71, 21, 151, 70, 75, 62, 250, 121, 148, 232, 65, 88, 131, 122, 94, 64, 142, 42, 45, 140, + 150, 124, 243, 242, 39, 207, 130, 176, 5, 244, 188, 128, 27, 84, 90, 23, 43, 248, 229, 227, + 78, 157, 3, 95, 10, 231, 119, 256, 54, 168, 180, 46, 86, 239, 201, 197, 156, 57, 6, 190, 20, + 205, 238, 255, 108, 79, 103, 92, 172, 221, 145, 137, 55, 114, 12, 123, 40, 153, 219, 253, + 216, 158, 206, 184, 87, 185, 33, 17, 110, 228, 24, 246, 80, 49, 181, 249, 175, 59, 155, 111, + 174, 113, 66, 34, 220, 199, 48, 235, 160, 98, 105, 241, 93, 118, 53, 222, 91, 226, 132, 68, + 183, 141, 96, 213, 63, 196, 210, 225, 186, 236, 106, 187, 182, 195, 7, 136, 109, 25, 192, + 169, 126, 135, 163, 193, 115, 215, 212, 117, 107, 133, 14, 15, 218, 50, 127, 81, 252, 13, + 69, 129, 230, 173, 167, 234, 214, 9, 28, 30, 179, 100, 254, 162, 247, 26, 138, 1, + ], + [ + 1, 204, 239, 183, 67, 47, 79, 182, 120, 65, 153, 115, 73, 243, 228, 252, 8, 90, 113, 179, + 22, 119, 118, 171, 189, 6, 196, 149, 70, 145, 25, 217, 64, 206, 133, 147, 176, 181, 173, 83, + 227, 48, 26, 164, 46, 132, 200, 194, 255, 106, 36, 148, 123, 163, 99, 150, 17, 127, 208, 27, + 111, 28, 58, 10, 241, 77, 31, 156, 213, 19, 21, 172, 136, 245, 122, 216, 117, 224, 207, 80, + 129, 102, 248, 220, 162, 152, 168, 91, 60, 161, 205, 186, 165, 250, 114, 126, 4, 45, 185, + 218, 11, 188, 59, 214, 223, 3, 98, 203, 35, 201, 141, 237, 32, 103, 195, 202, 88, 219, 215, + 170, 242, 24, 13, 82, 23, 66, 100, 97, 256, 53, 18, 74, 190, 210, 178, 75, 137, 192, 104, + 142, 184, 14, 29, 5, 249, 167, 144, 78, 235, 138, 139, 86, 68, 251, 61, 108, 187, 112, 232, + 40, 193, 51, 124, 110, 81, 76, 84, 174, 30, 209, 231, 93, 211, 125, 57, 63, 2, 151, 221, + 109, 134, 94, 158, 107, 240, 130, 49, 230, 146, 229, 199, 247, 16, 180, 226, 101, 44, 238, + 236, 85, 121, 12, 135, 41, 140, 33, 50, 177, 128, 155, 9, 37, 95, 105, 89, 166, 197, 96, 52, + 71, 92, 7, 143, 131, 253, 212, 72, 39, 246, 69, 198, 43, 34, 254, 159, 54, 222, 56, 116, 20, + 225, 154, 62, 55, 169, 38, 42, 87, 15, 233, 244, 175, 234, 191, 157, 160, 1, + ], + [ + 1, 205, 134, 228, 223, 226, 70, 215, 128, 26, 190, 143, 17, 144, 222, 21, 193, 244, 162, 57, + 120, 185, 146, 118, 32, 135, 176, 100, 197, 36, 184, 198, 241, 61, 169, 207, 30, 239, 165, + 158, 8, 98, 44, 25, 242, 9, 46, 178, 253, 208, 235, 116, 136, 124, 234, 168, 2, 153, 11, + 199, 189, 195, 140, 173, 256, 52, 123, 29, 34, 31, 187, 42, 129, 231, 67, 114, 240, 113, 35, + 236, 64, 13, 95, 200, 137, 72, 111, 139, 225, 122, 81, 157, 60, 221, 73, 59, 16, 196, 88, + 50, 227, 18, 92, 99, 249, 159, 213, 232, 15, 248, 211, 79, 4, 49, 22, 141, 121, 133, 23, 89, + 255, 104, 246, 58, 68, 62, 117, 84, 1, 205, 134, 228, 223, 226, 70, 215, 128, 26, 190, 143, + 17, 144, 222, 21, 193, 244, 162, 57, 120, 185, 146, 118, 32, 135, 176, 100, 197, 36, 184, + 198, 241, 61, 169, 207, 30, 239, 165, 158, 8, 98, 44, 25, 242, 9, 46, 178, 253, 208, 235, + 116, 136, 124, 234, 168, 2, 153, 11, 199, 189, 195, 140, 173, 256, 52, 123, 29, 34, 31, 187, + 42, 129, 231, 67, 114, 240, 113, 35, 236, 64, 13, 95, 200, 137, 72, 111, 139, 225, 122, 81, + 157, 60, 221, 73, 59, 16, 196, 88, 50, 227, 18, 92, 99, 249, 159, 213, 232, 15, 248, 211, + 79, 4, 49, 22, 141, 121, 133, 23, 89, 255, 104, 246, 58, 68, 62, 117, 84, 1, + ], + [ + 1, 206, 31, 218, 190, 76, 236, 43, 120, 48, 122, 203, 184, 125, 50, 20, 8, 106, 248, 202, + 235, 94, 89, 87, 189, 127, 205, 82, 187, 229, 143, 160, 64, 77, 185, 74, 81, 238, 198, 182, + 227, 245, 98, 142, 211, 33, 116, 252, 255, 102, 195, 78, 134, 105, 42, 171, 17, 161, 13, + 108, 146, 7, 157, 217, 241, 45, 18, 110, 44, 69, 79, 83, 136, 3, 104, 93, 140, 56, 228, 194, + 129, 103, 144, 109, 95, 38, 118, 150, 60, 24, 61, 230, 92, 191, 25, 10, 4, 53, 124, 101, + 246, 47, 173, 172, 223, 192, 231, 41, 222, 243, 200, 80, 32, 167, 221, 37, 169, 119, 99, 91, + 242, 251, 49, 71, 234, 145, 58, 126, 256, 51, 226, 39, 67, 181, 21, 214, 137, 209, 135, 54, + 73, 132, 207, 237, 249, 151, 9, 55, 22, 163, 168, 170, 68, 130, 52, 175, 70, 28, 114, 97, + 193, 180, 72, 183, 176, 19, 59, 75, 30, 12, 159, 115, 46, 224, 141, 5, 2, 155, 62, 179, 123, + 152, 215, 86, 240, 96, 244, 149, 111, 250, 100, 40, 16, 212, 239, 147, 213, 188, 178, 174, + 121, 254, 153, 164, 117, 201, 29, 63, 128, 154, 113, 148, 162, 219, 139, 107, 197, 233, 196, + 27, 165, 66, 232, 247, 253, 204, 133, 156, 11, 210, 84, 85, 34, 65, 26, 216, 35, 14, 57, + 177, 225, 90, 36, 220, 88, 138, 158, 166, 15, 6, 208, 186, 23, 112, 199, 131, 1, + ], + [ + 1, 207, 187, 159, 17, 178, 95, 133, 32, 199, 73, 205, 30, 42, 213, 144, 253, 200, 23, 135, + 189, 59, 134, 239, 129, 232, 222, 208, 137, 89, 176, 195, 16, 228, 165, 231, 15, 21, 235, + 72, 255, 100, 140, 196, 223, 158, 67, 248, 193, 116, 111, 104, 197, 173, 88, 226, 8, 114, + 211, 244, 136, 139, 246, 36, 256, 50, 70, 98, 240, 79, 162, 124, 225, 58, 184, 52, 227, 215, + 44, 113, 4, 57, 234, 122, 68, 198, 123, 18, 128, 25, 35, 49, 120, 168, 81, 62, 241, 29, 92, + 26, 242, 236, 22, 185, 2, 157, 117, 61, 34, 99, 190, 9, 64, 141, 146, 153, 60, 84, 169, 31, + 249, 143, 46, 13, 121, 118, 11, 221, 1, 207, 187, 159, 17, 178, 95, 133, 32, 199, 73, 205, + 30, 42, 213, 144, 253, 200, 23, 135, 189, 59, 134, 239, 129, 232, 222, 208, 137, 89, 176, + 195, 16, 228, 165, 231, 15, 21, 235, 72, 255, 100, 140, 196, 223, 158, 67, 248, 193, 116, + 111, 104, 197, 173, 88, 226, 8, 114, 211, 244, 136, 139, 246, 36, 256, 50, 70, 98, 240, 79, + 162, 124, 225, 58, 184, 52, 227, 215, 44, 113, 4, 57, 234, 122, 68, 198, 123, 18, 128, 25, + 35, 49, 120, 168, 81, 62, 241, 29, 92, 26, 242, 236, 22, 185, 2, 157, 117, 61, 34, 99, 190, + 9, 64, 141, 146, 153, 60, 84, 169, 31, 249, 143, 46, 13, 121, 118, 11, 221, 1, + ], + [ + 1, 208, 88, 57, 34, 133, 165, 139, 128, 153, 213, 100, 240, 62, 46, 59, 193, 52, 22, 207, + 137, 226, 234, 99, 32, 231, 246, 25, 60, 144, 140, 79, 241, 13, 134, 116, 227, 185, 187, 89, + 8, 122, 190, 199, 15, 36, 35, 84, 253, 196, 162, 29, 121, 239, 111, 215, 2, 159, 176, 114, + 68, 9, 73, 21, 256, 49, 169, 200, 223, 124, 92, 118, 129, 104, 44, 157, 17, 195, 211, 198, + 64, 205, 235, 50, 120, 31, 23, 158, 225, 26, 11, 232, 197, 113, 117, 178, 16, 244, 123, 141, + 30, 72, 70, 168, 249, 135, 67, 58, 242, 221, 222, 173, 4, 61, 95, 228, 136, 18, 146, 42, + 255, 98, 81, 143, 189, 248, 184, 236, 1, 208, 88, 57, 34, 133, 165, 139, 128, 153, 213, 100, + 240, 62, 46, 59, 193, 52, 22, 207, 137, 226, 234, 99, 32, 231, 246, 25, 60, 144, 140, 79, + 241, 13, 134, 116, 227, 185, 187, 89, 8, 122, 190, 199, 15, 36, 35, 84, 253, 196, 162, 29, + 121, 239, 111, 215, 2, 159, 176, 114, 68, 9, 73, 21, 256, 49, 169, 200, 223, 124, 92, 118, + 129, 104, 44, 157, 17, 195, 211, 198, 64, 205, 235, 50, 120, 31, 23, 158, 225, 26, 11, 232, + 197, 113, 117, 178, 16, 244, 123, 141, 30, 72, 70, 168, 249, 135, 67, 58, 242, 221, 222, + 173, 4, 61, 95, 228, 136, 18, 146, 42, 255, 98, 81, 143, 189, 248, 184, 236, 1, + ], + [ + 1, 209, 248, 175, 81, 224, 42, 40, 136, 154, 61, 156, 222, 138, 58, 43, 249, 127, 72, 142, + 123, 7, 178, 194, 197, 53, 26, 37, 23, 181, 50, 170, 64, 12, 195, 149, 44, 201, 118, 247, + 223, 90, 49, 218, 73, 94, 114, 182, 2, 161, 239, 93, 162, 191, 84, 80, 15, 51, 122, 55, 187, + 19, 116, 86, 241, 254, 144, 27, 246, 14, 99, 131, 137, 106, 52, 74, 46, 105, 100, 83, 128, + 24, 133, 41, 88, 145, 236, 237, 189, 180, 98, 179, 146, 188, 228, 107, 4, 65, 221, 186, 67, + 125, 168, 160, 30, 102, 244, 110, 117, 38, 232, 172, 225, 251, 31, 54, 235, 28, 198, 5, 17, + 212, 104, 148, 92, 210, 200, 166, 256, 48, 9, 82, 176, 33, 215, 217, 121, 103, 196, 101, 35, + 119, 199, 214, 8, 130, 185, 115, 134, 250, 79, 63, 60, 204, 231, 220, 234, 76, 207, 87, 193, + 245, 62, 108, 213, 56, 139, 10, 34, 167, 208, 39, 184, 163, 143, 75, 255, 96, 18, 164, 95, + 66, 173, 177, 242, 206, 135, 202, 70, 238, 141, 171, 16, 3, 113, 230, 11, 243, 158, 126, + 120, 151, 205, 183, 211, 152, 157, 174, 129, 233, 124, 216, 169, 112, 21, 20, 68, 77, 159, + 78, 111, 69, 29, 150, 253, 192, 36, 71, 190, 132, 89, 97, 227, 155, 13, 147, 140, 219, 25, + 85, 32, 6, 226, 203, 22, 229, 59, 252, 240, 45, 153, 109, 165, 47, 57, 91, 1, + ], + [ + 1, 210, 153, 5, 22, 251, 25, 110, 227, 125, 36, 107, 111, 180, 21, 41, 129, 105, 205, 131, + 11, 254, 141, 55, 242, 191, 18, 182, 184, 90, 139, 149, 193, 181, 231, 194, 134, 127, 199, + 156, 121, 224, 9, 91, 92, 45, 198, 203, 225, 219, 244, 97, 67, 192, 228, 78, 189, 112, 133, + 174, 46, 151, 99, 230, 241, 238, 122, 177, 162, 96, 114, 39, 223, 56, 195, 87, 23, 204, 178, + 115, 249, 119, 61, 217, 81, 48, 57, 148, 240, 28, 226, 172, 140, 102, 89, 186, 253, 188, + 159, 237, 169, 24, 157, 74, 120, 14, 113, 86, 70, 51, 173, 93, 255, 94, 208, 247, 213, 12, + 207, 37, 60, 7, 185, 43, 35, 154, 215, 175, 256, 47, 104, 252, 235, 6, 232, 147, 30, 132, + 221, 150, 146, 77, 236, 216, 128, 152, 52, 126, 246, 3, 116, 202, 15, 66, 239, 75, 73, 167, + 118, 108, 64, 76, 26, 63, 123, 130, 58, 101, 136, 33, 248, 166, 165, 212, 59, 54, 32, 38, + 13, 160, 190, 65, 29, 179, 68, 145, 124, 83, 211, 106, 158, 27, 16, 19, 135, 80, 95, 161, + 143, 218, 34, 201, 62, 170, 234, 53, 79, 142, 8, 138, 196, 40, 176, 209, 200, 109, 17, 229, + 31, 85, 117, 155, 168, 71, 4, 69, 98, 20, 88, 233, 100, 183, 137, 243, 144, 171, 187, 206, + 84, 164, 2, 163, 49, 10, 44, 245, 50, 220, 197, 250, 72, 214, 222, 103, 42, 82, 1, + ], + [ + 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, + 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, + 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, + 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, 146, 223, 22, 16, + 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, 46, 197, 190, 255, + 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, 225, 187, 136, 169, + 193, 117, 15, 81, 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, 4, 73, 240, 11, 8, + 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, 23, 227, 95, 256, + 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, 241, 222, 68, 213, + 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1, 211, 60, 67, 2, 165, 120, 134, + 4, 73, 240, 11, 8, 146, 223, 22, 16, 35, 189, 44, 32, 70, 121, 88, 64, 140, 242, 176, 128, + 23, 227, 95, 256, 46, 197, 190, 255, 92, 137, 123, 253, 184, 17, 246, 249, 111, 34, 235, + 241, 222, 68, 213, 225, 187, 136, 169, 193, 117, 15, 81, 129, 234, 30, 162, 1, + ], + [ + 1, 212, 226, 110, 190, 188, 21, 83, 120, 254, 135, 93, 184, 201, 207, 194, 8, 154, 9, 109, + 235, 219, 168, 150, 189, 233, 52, 230, 187, 66, 114, 10, 64, 204, 72, 101, 81, 210, 59, 172, + 227, 65, 159, 41, 211, 14, 141, 80, 255, 90, 62, 37, 134, 138, 215, 91, 17, 6, 244, 71, 146, + 112, 100, 126, 241, 206, 239, 39, 44, 76, 178, 214, 136, 48, 153, 54, 140, 125, 29, 237, + 129, 106, 113, 55, 95, 94, 139, 170, 60, 127, 196, 175, 92, 229, 232, 97, 4, 77, 133, 183, + 246, 238, 84, 75, 223, 245, 26, 115, 222, 33, 57, 5, 32, 102, 36, 179, 169, 105, 158, 86, + 242, 161, 208, 149, 234, 7, 199, 40, 256, 45, 31, 147, 67, 69, 236, 174, 137, 3, 122, 164, + 73, 56, 50, 63, 249, 103, 248, 148, 22, 38, 89, 107, 68, 24, 205, 27, 70, 191, 143, 247, + 193, 53, 185, 156, 176, 47, 198, 85, 30, 192, 98, 216, 46, 243, 116, 177, 2, 167, 195, 220, + 123, 119, 42, 166, 240, 251, 13, 186, 111, 145, 157, 131, 16, 51, 18, 218, 213, 181, 79, 43, + 121, 209, 104, 203, 117, 132, 228, 20, 128, 151, 144, 202, 162, 163, 118, 87, 197, 130, 61, + 82, 165, 28, 25, 160, 253, 180, 124, 74, 11, 19, 173, 182, 34, 12, 231, 142, 35, 224, 200, + 252, 225, 155, 221, 78, 88, 152, 99, 171, 15, 96, 49, 108, 23, 250, 58, 217, 1, + ], + [ + 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, + 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, + 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, + 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, 255, 88, 240, 234, + 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, 256, 44, 120, 117, + 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, 128, 22, 60, 187, + 253, 176, 223, 211, 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, 64, 11, 30, 222, + 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, 134, 15, 111, + 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, 67, 136, 184, + 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1, 213, 137, 140, 8, 162, 68, 92, + 64, 11, 30, 222, 255, 88, 240, 234, 241, 190, 121, 73, 129, 235, 197, 70, 4, 81, 34, 46, 32, + 134, 15, 111, 256, 44, 120, 117, 249, 95, 189, 165, 193, 246, 227, 35, 2, 169, 17, 23, 16, + 67, 136, 184, 128, 22, 60, 187, 253, 176, 223, 211, 225, 123, 242, 146, 1, + ], + [ + 1, 214, 50, 163, 187, 183, 98, 155, 17, 40, 79, 201, 95, 27, 124, 65, 32, 166, 58, 76, 73, + 202, 52, 77, 30, 252, 215, 7, 213, 93, 113, 24, 253, 172, 57, 119, 23, 39, 122, 151, 189, + 97, 198, 224, 134, 149, 18, 254, 129, 107, 25, 210, 222, 220, 49, 206, 137, 20, 168, 229, + 176, 142, 62, 161, 16, 83, 29, 38, 165, 101, 26, 167, 15, 126, 236, 132, 235, 175, 185, 12, + 255, 86, 157, 188, 140, 148, 61, 204, 223, 177, 99, 112, 67, 203, 9, 127, 193, 182, 141, + 105, 111, 110, 153, 103, 197, 10, 84, 243, 88, 71, 31, 209, 8, 170, 143, 19, 211, 179, 13, + 212, 136, 63, 118, 66, 246, 216, 221, 6, 256, 43, 207, 94, 70, 74, 159, 102, 240, 217, 178, + 56, 162, 230, 133, 192, 225, 91, 199, 181, 184, 55, 205, 180, 227, 5, 42, 250, 44, 164, 144, + 233, 4, 85, 200, 138, 234, 218, 135, 106, 68, 160, 59, 33, 123, 108, 239, 3, 128, 150, 232, + 47, 35, 37, 208, 51, 120, 237, 89, 28, 81, 115, 195, 96, 241, 174, 228, 219, 92, 156, 231, + 90, 242, 131, 21, 125, 22, 82, 72, 245, 2, 171, 100, 69, 117, 109, 196, 53, 34, 80, 158, + 145, 190, 54, 248, 130, 64, 75, 116, 152, 146, 147, 104, 154, 60, 247, 173, 14, 169, 186, + 226, 48, 249, 87, 114, 238, 46, 78, 244, 45, 121, 194, 139, 191, 11, 41, 36, 251, 1, + ], + [ + 1, 215, 222, 185, 197, 207, 44, 208, 2, 173, 187, 113, 137, 157, 88, 159, 4, 89, 117, 226, + 17, 57, 176, 61, 8, 178, 234, 195, 34, 114, 95, 122, 16, 99, 211, 133, 68, 228, 190, 244, + 32, 198, 165, 9, 136, 199, 123, 231, 64, 139, 73, 18, 15, 141, 246, 205, 128, 21, 146, 36, + 30, 25, 235, 153, 256, 42, 35, 72, 60, 50, 213, 49, 255, 84, 70, 144, 120, 100, 169, 98, + 253, 168, 140, 31, 240, 200, 81, 196, 249, 79, 23, 62, 223, 143, 162, 135, 241, 158, 46, + 124, 189, 29, 67, 13, 225, 59, 92, 248, 121, 58, 134, 26, 193, 118, 184, 239, 242, 116, 11, + 52, 129, 236, 111, 221, 227, 232, 22, 104, 1, 215, 222, 185, 197, 207, 44, 208, 2, 173, 187, + 113, 137, 157, 88, 159, 4, 89, 117, 226, 17, 57, 176, 61, 8, 178, 234, 195, 34, 114, 95, + 122, 16, 99, 211, 133, 68, 228, 190, 244, 32, 198, 165, 9, 136, 199, 123, 231, 64, 139, 73, + 18, 15, 141, 246, 205, 128, 21, 146, 36, 30, 25, 235, 153, 256, 42, 35, 72, 60, 50, 213, 49, + 255, 84, 70, 144, 120, 100, 169, 98, 253, 168, 140, 31, 240, 200, 81, 196, 249, 79, 23, 62, + 223, 143, 162, 135, 241, 158, 46, 124, 189, 29, 67, 13, 225, 59, 92, 248, 121, 58, 134, 26, + 193, 118, 184, 239, 242, 116, 11, 52, 129, 236, 111, 221, 227, 232, 22, 104, 1, + ], + [ + 1, 216, 139, 212, 46, 170, 226, 243, 60, 110, 116, 127, 190, 177, 196, 188, 2, 175, 21, 167, + 92, 83, 195, 229, 120, 220, 232, 254, 123, 97, 135, 119, 4, 93, 42, 77, 184, 166, 133, 201, + 240, 183, 207, 251, 246, 194, 13, 238, 8, 186, 84, 154, 111, 75, 9, 145, 223, 109, 157, 245, + 235, 131, 26, 219, 16, 115, 168, 51, 222, 150, 18, 33, 189, 218, 57, 233, 213, 5, 52, 181, + 32, 230, 79, 102, 187, 43, 36, 66, 121, 179, 114, 209, 169, 10, 104, 105, 64, 203, 158, 204, + 117, 86, 72, 132, 242, 101, 228, 161, 81, 20, 208, 210, 128, 149, 59, 151, 234, 172, 144, 7, + 227, 202, 199, 65, 162, 40, 159, 163, 256, 41, 118, 45, 211, 87, 31, 14, 197, 147, 141, 130, + 67, 80, 61, 69, 255, 82, 236, 90, 165, 174, 62, 28, 137, 37, 25, 3, 134, 160, 122, 138, 253, + 164, 215, 180, 73, 91, 124, 56, 17, 74, 50, 6, 11, 63, 244, 19, 249, 71, 173, 103, 146, 182, + 248, 112, 34, 148, 100, 12, 22, 126, 231, 38, 241, 142, 89, 206, 35, 107, 239, 224, 68, 39, + 200, 24, 44, 252, 205, 76, 225, 27, 178, 155, 70, 214, 221, 191, 136, 78, 143, 48, 88, 247, + 153, 152, 193, 54, 99, 53, 140, 171, 185, 125, 15, 156, 29, 96, 176, 237, 49, 47, 129, 108, + 198, 106, 23, 85, 113, 250, 30, 55, 58, 192, 95, 217, 98, 94, 1, + ], + [ + 1, 217, 58, 250, 23, 108, 49, 96, 15, 171, 99, 152, 88, 78, 221, 155, 225, 252, 200, 224, + 35, 142, 231, 12, 34, 182, 173, 19, 11, 74, 124, 180, 253, 160, 25, 28, 165, 82, 61, 130, + 197, 87, 118, 163, 162, 202, 144, 151, 128, 20, 228, 132, 117, 203, 104, 209, 121, 43, 79, + 181, 213, 218, 18, 51, 16, 131, 157, 145, 111, 186, 13, 251, 240, 166, 42, 119, 123, 220, + 195, 167, 2, 177, 116, 243, 46, 216, 98, 192, 30, 85, 198, 47, 176, 156, 185, 53, 193, 247, + 143, 191, 70, 27, 205, 24, 68, 107, 89, 38, 22, 148, 248, 103, 249, 63, 50, 56, 73, 164, + 122, 3, 137, 174, 236, 69, 67, 147, 31, 45, 256, 40, 199, 7, 234, 149, 208, 161, 242, 86, + 158, 105, 169, 179, 36, 102, 32, 5, 57, 33, 222, 115, 26, 245, 223, 75, 84, 238, 246, 183, + 133, 77, 4, 97, 232, 229, 92, 175, 196, 127, 60, 170, 139, 94, 95, 55, 113, 106, 129, 237, + 29, 125, 140, 54, 153, 48, 136, 214, 178, 76, 44, 39, 239, 206, 241, 126, 100, 112, 146, 71, + 244, 6, 17, 91, 215, 138, 134, 37, 62, 90, 255, 80, 141, 14, 211, 41, 159, 65, 227, 172, 59, + 210, 81, 101, 72, 204, 64, 10, 114, 66, 187, 230, 52, 233, 189, 150, 168, 219, 235, 109, 9, + 154, 8, 194, 207, 201, 184, 93, 135, 254, 120, 83, 21, 188, 190, 110, 226, 212, 1, + ], + [ + 1, 218, 236, 48, 184, 20, 248, 94, 189, 82, 143, 77, 81, 182, 98, 33, 255, 78, 42, 161, 146, + 217, 18, 69, 136, 93, 228, 103, 95, 150, 61, 191, 4, 101, 173, 192, 222, 80, 221, 119, 242, + 71, 58, 51, 67, 214, 135, 132, 249, 55, 168, 130, 70, 97, 72, 19, 30, 115, 141, 155, 123, + 86, 244, 250, 16, 147, 178, 254, 117, 63, 113, 219, 197, 27, 232, 204, 11, 85, 26, 14, 225, + 220, 158, 6, 23, 131, 31, 76, 120, 203, 50, 106, 235, 87, 205, 229, 64, 74, 198, 245, 211, + 252, 195, 105, 17, 108, 157, 45, 44, 83, 104, 56, 129, 109, 118, 24, 92, 10, 124, 47, 223, + 41, 200, 167, 169, 91, 49, 145, 256, 39, 21, 209, 73, 237, 9, 163, 68, 175, 114, 180, 176, + 75, 159, 224, 2, 179, 215, 96, 111, 40, 239, 188, 121, 164, 29, 154, 162, 107, 196, 66, 253, + 156, 84, 65, 35, 177, 36, 138, 15, 186, 199, 206, 190, 43, 122, 125, 8, 202, 89, 127, 187, + 160, 185, 238, 227, 142, 116, 102, 134, 171, 13, 7, 241, 110, 79, 3, 140, 194, 144, 38, 60, + 230, 25, 53, 246, 172, 231, 243, 32, 37, 99, 251, 234, 126, 226, 181, 137, 54, 207, 151, 22, + 170, 52, 28, 193, 183, 59, 12, 46, 5, 62, 152, 240, 149, 100, 212, 213, 174, 153, 201, 128, + 148, 139, 233, 165, 247, 133, 210, 34, 216, 57, 90, 88, 166, 208, 112, 1, + ], + [ + 1, 219, 159, 126, 95, 245, 199, 148, 30, 145, 144, 182, 23, 154, 59, 71, 129, 238, 208, 63, + 176, 251, 228, 74, 15, 201, 72, 91, 140, 77, 158, 164, 193, 119, 104, 160, 88, 254, 114, 37, + 136, 229, 36, 174, 70, 167, 79, 82, 225, 188, 52, 80, 44, 127, 57, 147, 68, 243, 18, 87, 35, + 212, 168, 41, 241, 94, 26, 40, 22, 192, 157, 202, 34, 250, 9, 172, 146, 106, 84, 149, 249, + 47, 13, 20, 11, 96, 207, 101, 17, 125, 133, 86, 73, 53, 42, 203, 253, 152, 135, 10, 134, 48, + 232, 179, 137, 191, 195, 43, 165, 155, 21, 230, 255, 76, 196, 5, 67, 24, 116, 218, 197, 224, + 226, 150, 211, 206, 139, 115, 256, 38, 98, 131, 162, 12, 58, 109, 227, 112, 113, 75, 234, + 103, 198, 186, 128, 19, 49, 194, 81, 6, 29, 183, 242, 56, 185, 166, 117, 180, 99, 93, 64, + 138, 153, 97, 169, 3, 143, 220, 121, 28, 221, 83, 187, 90, 178, 175, 32, 69, 205, 177, 213, + 130, 200, 110, 189, 14, 239, 170, 222, 45, 89, 216, 16, 163, 231, 217, 235, 65, 100, 55, + 223, 7, 248, 85, 111, 151, 173, 108, 8, 210, 244, 237, 246, 161, 50, 156, 240, 132, 124, + 171, 184, 204, 215, 54, 4, 105, 122, 247, 123, 209, 25, 78, 120, 66, 62, 214, 92, 102, 236, + 27, 2, 181, 61, 252, 190, 233, 141, 39, 60, 33, 31, 107, 46, 51, 118, 142, 1, + ], + [ + 1, 220, 84, 233, 117, 40, 62, 19, 68, 54, 58, 167, 246, 150, 104, 7, 255, 74, 89, 48, 23, + 177, 133, 219, 121, 149, 141, 180, 22, 214, 49, 243, 4, 109, 79, 161, 211, 160, 248, 76, 15, + 216, 232, 154, 213, 86, 159, 28, 249, 39, 99, 192, 92, 194, 18, 105, 227, 82, 50, 206, 88, + 85, 196, 201, 16, 179, 59, 130, 73, 126, 221, 47, 60, 93, 157, 102, 81, 87, 122, 112, 225, + 156, 139, 254, 111, 5, 72, 163, 137, 71, 200, 53, 95, 83, 13, 33, 64, 202, 236, 6, 35, 247, + 113, 188, 240, 115, 114, 151, 67, 91, 231, 191, 129, 110, 42, 245, 187, 20, 31, 138, 34, 27, + 29, 212, 123, 75, 52, 132, 256, 37, 173, 24, 140, 217, 195, 238, 189, 203, 199, 90, 11, 107, + 153, 250, 2, 183, 168, 209, 234, 80, 124, 38, 136, 108, 116, 77, 235, 43, 208, 14, 253, 148, + 178, 96, 46, 97, 9, 181, 242, 41, 25, 103, 44, 171, 98, 229, 8, 218, 158, 65, 165, 63, 239, + 152, 30, 175, 207, 51, 169, 172, 61, 56, 241, 78, 198, 127, 184, 131, 36, 210, 197, 164, + 100, 155, 176, 170, 135, 145, 32, 101, 118, 3, 146, 252, 185, 94, 120, 186, 57, 204, 162, + 174, 244, 224, 193, 55, 21, 251, 222, 10, 144, 69, 17, 142, 143, 106, 190, 166, 26, 66, 128, + 147, 215, 12, 70, 237, 226, 119, 223, 230, 228, 45, 134, 182, 205, 125, 1, + ], + [ + 1, 221, 11, 118, 121, 13, 46, 143, 249, 31, 169, 84, 60, 153, 146, 141, 64, 9, 190, 99, 34, + 61, 117, 157, 2, 185, 22, 236, 242, 26, 92, 29, 241, 62, 81, 168, 120, 49, 35, 25, 128, 18, + 123, 198, 68, 122, 234, 57, 4, 113, 44, 215, 227, 52, 184, 58, 225, 124, 162, 79, 240, 98, + 70, 50, 256, 36, 246, 139, 136, 244, 211, 114, 8, 226, 88, 173, 197, 104, 111, 116, 193, + 248, 67, 158, 223, 196, 140, 100, 255, 72, 235, 21, 15, 231, 165, 228, 16, 195, 176, 89, + 137, 208, 222, 232, 129, 239, 134, 59, 189, 135, 23, 200, 253, 144, 213, 42, 30, 205, 73, + 199, 32, 133, 95, 178, 17, 159, 187, 207, 1, 221, 11, 118, 121, 13, 46, 143, 249, 31, 169, + 84, 60, 153, 146, 141, 64, 9, 190, 99, 34, 61, 117, 157, 2, 185, 22, 236, 242, 26, 92, 29, + 241, 62, 81, 168, 120, 49, 35, 25, 128, 18, 123, 198, 68, 122, 234, 57, 4, 113, 44, 215, + 227, 52, 184, 58, 225, 124, 162, 79, 240, 98, 70, 50, 256, 36, 246, 139, 136, 244, 211, 114, + 8, 226, 88, 173, 197, 104, 111, 116, 193, 248, 67, 158, 223, 196, 140, 100, 255, 72, 235, + 21, 15, 231, 165, 228, 16, 195, 176, 89, 137, 208, 222, 232, 129, 239, 134, 59, 189, 135, + 23, 200, 253, 144, 213, 42, 30, 205, 73, 199, 32, 133, 95, 178, 17, 159, 187, 207, 1, + ], + [ + 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, + 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, + 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, + 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, 234, 34, 95, 16, + 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, 35, 60, 213, 255, + 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, 92, 121, 134, + 193, 184, 242, 11, 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, 117, 17, 176, 8, + 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, 146, 30, 235, 256, + 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, 241, 46, 189, 67, 225, + 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1, 222, 197, 44, 2, 187, 137, 88, 4, + 117, 17, 176, 8, 234, 34, 95, 16, 211, 68, 190, 32, 165, 136, 123, 64, 73, 15, 246, 128, + 146, 30, 235, 256, 35, 60, 213, 255, 70, 120, 169, 253, 140, 240, 81, 249, 23, 223, 162, + 241, 46, 189, 67, 225, 92, 121, 134, 193, 184, 242, 11, 129, 111, 227, 22, 1, + ], + [ + 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, + 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, + 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, + 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, + 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, + 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, + 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, + 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, + 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, + 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, + 242, 253, 136, 2, 189, 256, 34, 129, 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, + 68, 1, 223, 128, 17, 193, 120, 32, 197, 241, 30, 8, 242, 253, 136, 2, 189, 256, 34, 129, + 240, 64, 137, 225, 60, 16, 227, 249, 15, 4, 121, 255, 68, 1, + ], + [ + 1, 224, 61, 43, 123, 53, 50, 149, 223, 94, 239, 80, 187, 254, 99, 74, 128, 145, 98, 107, 67, + 102, 232, 54, 17, 210, 9, 217, 35, 130, 79, 220, 193, 56, 208, 75, 95, 206, 141, 230, 120, + 152, 124, 20, 111, 192, 89, 147, 32, 229, 153, 91, 81, 154, 58, 142, 197, 181, 195, 247, 73, + 161, 84, 55, 241, 14, 52, 83, 88, 180, 228, 186, 30, 38, 31, 5, 92, 48, 215, 101, 8, 250, + 231, 87, 213, 167, 143, 164, 242, 238, 113, 126, 211, 233, 21, 78, 253, 132, 13, 85, 22, 45, + 57, 175, 136, 138, 72, 194, 23, 12, 118, 218, 2, 191, 122, 86, 246, 106, 100, 41, 189, 188, + 221, 160, 117, 251, 198, 148, 256, 33, 196, 214, 134, 204, 207, 108, 34, 163, 18, 177, 70, + 3, 158, 183, 129, 112, 159, 150, 190, 155, 25, 203, 240, 47, 248, 40, 222, 127, 178, 37, 64, + 201, 49, 182, 162, 51, 116, 27, 137, 105, 133, 237, 146, 65, 168, 110, 225, 28, 104, 166, + 176, 103, 199, 115, 60, 76, 62, 10, 184, 96, 173, 202, 16, 243, 205, 174, 169, 77, 29, 71, + 227, 219, 226, 252, 165, 209, 42, 156, 249, 7, 26, 170, 44, 90, 114, 93, 15, 19, 144, 131, + 46, 24, 236, 179, 4, 125, 244, 172, 235, 212, 200, 82, 121, 119, 185, 63, 234, 245, 139, 39, + 255, 66, 135, 171, 11, 151, 157, 216, 68, 69, 36, 97, 140, 6, 59, 109, 1, + ], + [ + 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, + 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, + 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, + 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, + 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, + 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, + 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, + 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, + 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, + 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, + 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, + 249, 256, 32, 4, 129, 241, 255, 64, 8, 1, 225, 253, 128, 16, 2, 193, 249, 256, 32, 4, 129, + 241, 255, 64, 8, 1, + ], + [ + 1, 226, 190, 21, 120, 135, 184, 207, 8, 9, 235, 168, 189, 52, 187, 114, 64, 72, 81, 59, 227, + 159, 211, 141, 255, 62, 134, 215, 17, 244, 146, 100, 241, 239, 44, 178, 136, 153, 140, 29, + 129, 113, 95, 139, 60, 196, 92, 232, 4, 133, 246, 84, 223, 26, 222, 57, 32, 36, 169, 158, + 242, 208, 234, 199, 256, 31, 67, 236, 137, 122, 73, 50, 249, 248, 22, 89, 68, 205, 70, 143, + 193, 185, 176, 198, 30, 98, 46, 116, 2, 195, 123, 42, 240, 13, 111, 157, 16, 18, 213, 79, + 121, 104, 117, 228, 128, 144, 162, 118, 197, 61, 165, 25, 253, 124, 11, 173, 34, 231, 35, + 200, 225, 221, 88, 99, 15, 49, 23, 58, 1, 226, 190, 21, 120, 135, 184, 207, 8, 9, 235, 168, + 189, 52, 187, 114, 64, 72, 81, 59, 227, 159, 211, 141, 255, 62, 134, 215, 17, 244, 146, 100, + 241, 239, 44, 178, 136, 153, 140, 29, 129, 113, 95, 139, 60, 196, 92, 232, 4, 133, 246, 84, + 223, 26, 222, 57, 32, 36, 169, 158, 242, 208, 234, 199, 256, 31, 67, 236, 137, 122, 73, 50, + 249, 248, 22, 89, 68, 205, 70, 143, 193, 185, 176, 198, 30, 98, 46, 116, 2, 195, 123, 42, + 240, 13, 111, 157, 16, 18, 213, 79, 121, 104, 117, 228, 128, 144, 162, 118, 197, 61, 165, + 25, 253, 124, 11, 173, 34, 231, 35, 200, 225, 221, 88, 99, 15, 49, 23, 58, 1, + ], + [ + 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, + 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, + 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, + 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, + 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, + 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, + 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, + 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, + 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, + 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, + 240, 253, 120, 255, 60, 256, 30, 128, 15, 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, + 227, 129, 242, 193, 121, 225, 189, 241, 223, 249, 240, 253, 120, 255, 60, 256, 30, 128, 15, + 64, 136, 32, 68, 16, 34, 8, 17, 4, 137, 2, 197, 1, + ], + [ + 1, 228, 70, 26, 17, 21, 162, 185, 32, 100, 184, 61, 30, 158, 44, 9, 253, 116, 234, 153, 189, + 173, 123, 31, 129, 114, 35, 13, 137, 139, 81, 221, 16, 50, 92, 159, 15, 79, 22, 133, 255, + 58, 117, 205, 223, 215, 190, 144, 193, 57, 146, 135, 197, 198, 169, 239, 8, 25, 46, 208, + 136, 168, 11, 195, 256, 29, 187, 231, 240, 236, 95, 72, 225, 157, 73, 196, 227, 99, 213, + 248, 4, 141, 23, 104, 68, 84, 134, 226, 128, 143, 222, 244, 120, 118, 176, 36, 241, 207, + 165, 98, 242, 178, 235, 124, 2, 199, 140, 52, 34, 42, 67, 113, 64, 200, 111, 122, 60, 59, + 88, 18, 249, 232, 211, 49, 121, 89, 246, 62, 1, 228, 70, 26, 17, 21, 162, 185, 32, 100, 184, + 61, 30, 158, 44, 9, 253, 116, 234, 153, 189, 173, 123, 31, 129, 114, 35, 13, 137, 139, 81, + 221, 16, 50, 92, 159, 15, 79, 22, 133, 255, 58, 117, 205, 223, 215, 190, 144, 193, 57, 146, + 135, 197, 198, 169, 239, 8, 25, 46, 208, 136, 168, 11, 195, 256, 29, 187, 231, 240, 236, 95, + 72, 225, 157, 73, 196, 227, 99, 213, 248, 4, 141, 23, 104, 68, 84, 134, 226, 128, 143, 222, + 244, 120, 118, 176, 36, 241, 207, 165, 98, 242, 178, 235, 124, 2, 199, 140, 52, 34, 42, 67, + 113, 64, 200, 111, 122, 60, 59, 88, 18, 249, 232, 211, 49, 121, 89, 246, 62, 1, + ], + [ + 1, 229, 13, 150, 169, 151, 141, 164, 34, 76, 185, 217, 92, 251, 168, 179, 128, 14, 122, 182, + 44, 53, 58, 175, 240, 219, 36, 20, 211, 3, 173, 39, 193, 250, 196, 166, 235, 102, 228, 41, + 137, 19, 239, 247, 23, 127, 42, 109, 32, 132, 159, 174, 11, 206, 143, 108, 60, 119, 9, 5, + 117, 65, 236, 74, 241, 191, 49, 170, 123, 154, 57, 203, 227, 69, 124, 126, 70, 96, 139, 220, + 8, 33, 104, 172, 67, 180, 100, 27, 15, 94, 195, 194, 222, 209, 59, 147, 253, 112, 205, 171, + 95, 167, 207, 115, 121, 210, 31, 160, 146, 24, 99, 55, 2, 201, 26, 43, 81, 45, 25, 71, 68, + 152, 113, 177, 184, 245, 79, 101, 256, 28, 244, 107, 88, 106, 116, 93, 223, 181, 72, 40, + 165, 6, 89, 78, 129, 243, 135, 75, 213, 204, 199, 82, 17, 38, 221, 237, 46, 254, 84, 218, + 64, 7, 61, 91, 22, 155, 29, 216, 120, 238, 18, 10, 234, 130, 215, 148, 225, 125, 98, 83, + 246, 51, 114, 149, 197, 138, 248, 252, 140, 192, 21, 183, 16, 66, 208, 87, 134, 103, 200, + 54, 30, 188, 133, 131, 187, 161, 118, 37, 249, 224, 153, 85, 190, 77, 157, 230, 242, 163, + 62, 63, 35, 48, 198, 110, 4, 145, 52, 86, 162, 90, 50, 142, 136, 47, 226, 97, 111, 233, 158, + 202, 255, 56, 231, 214, 176, 212, 232, 186, 189, 105, 144, 80, 73, 12, 178, 156, 1, + ], + [ + 1, 230, 215, 106, 222, 174, 185, 145, 197, 78, 207, 65, 44, 97, 208, 38, 2, 203, 173, 212, + 187, 91, 113, 33, 137, 156, 157, 130, 88, 194, 159, 76, 4, 149, 89, 167, 117, 182, 226, 66, + 17, 55, 57, 3, 176, 131, 61, 152, 8, 41, 178, 77, 234, 107, 195, 132, 34, 110, 114, 6, 95, + 5, 122, 47, 16, 82, 99, 154, 211, 214, 133, 7, 68, 220, 228, 12, 190, 10, 244, 94, 32, 164, + 198, 51, 165, 171, 9, 14, 136, 183, 199, 24, 123, 20, 231, 188, 64, 71, 139, 102, 73, 85, + 18, 28, 15, 109, 141, 48, 246, 40, 205, 119, 128, 142, 21, 204, 146, 170, 36, 56, 30, 218, + 25, 96, 235, 80, 153, 238, 256, 27, 42, 151, 35, 83, 72, 112, 60, 179, 50, 192, 213, 160, + 49, 219, 255, 54, 84, 45, 70, 166, 144, 224, 120, 101, 100, 127, 169, 63, 98, 181, 253, 108, + 168, 90, 140, 75, 31, 191, 240, 202, 200, 254, 81, 126, 196, 105, 249, 216, 79, 180, 23, + 150, 62, 125, 223, 147, 143, 251, 162, 252, 135, 210, 241, 175, 158, 103, 46, 43, 124, 250, + 189, 37, 29, 245, 67, 247, 13, 163, 225, 93, 59, 206, 92, 86, 248, 243, 121, 74, 58, 233, + 134, 237, 26, 69, 193, 186, 118, 155, 184, 172, 239, 229, 242, 148, 116, 209, 11, 217, 52, + 138, 129, 115, 236, 53, 111, 87, 221, 201, 227, 39, 232, 161, 22, 177, 104, 19, 1, + ], + [ + 1, 231, 162, 157, 30, 248, 234, 84, 129, 244, 81, 207, 15, 124, 117, 42, 193, 122, 169, 232, + 136, 62, 187, 21, 225, 61, 213, 116, 68, 31, 222, 139, 241, 159, 235, 58, 34, 144, 111, 198, + 249, 208, 246, 29, 17, 72, 184, 99, 253, 104, 123, 143, 137, 36, 92, 178, 255, 52, 190, 200, + 197, 18, 46, 89, 256, 26, 95, 100, 227, 9, 23, 173, 128, 13, 176, 50, 242, 133, 140, 215, + 64, 135, 88, 25, 121, 195, 70, 236, 32, 196, 44, 141, 189, 226, 35, 118, 16, 98, 22, 199, + 223, 113, 146, 59, 8, 49, 11, 228, 240, 185, 73, 158, 4, 153, 134, 114, 120, 221, 165, 79, + 2, 205, 67, 57, 60, 239, 211, 168, 1, 231, 162, 157, 30, 248, 234, 84, 129, 244, 81, 207, + 15, 124, 117, 42, 193, 122, 169, 232, 136, 62, 187, 21, 225, 61, 213, 116, 68, 31, 222, 139, + 241, 159, 235, 58, 34, 144, 111, 198, 249, 208, 246, 29, 17, 72, 184, 99, 253, 104, 123, + 143, 137, 36, 92, 178, 255, 52, 190, 200, 197, 18, 46, 89, 256, 26, 95, 100, 227, 9, 23, + 173, 128, 13, 176, 50, 242, 133, 140, 215, 64, 135, 88, 25, 121, 195, 70, 236, 32, 196, 44, + 141, 189, 226, 35, 118, 16, 98, 22, 199, 223, 113, 146, 59, 8, 49, 11, 228, 240, 185, 73, + 158, 4, 153, 134, 114, 120, 221, 165, 79, 2, 205, 67, 57, 60, 239, 211, 168, 1, + ], + [ + 1, 232, 111, 52, 242, 118, 134, 248, 225, 29, 46, 135, 223, 79, 81, 31, 253, 100, 70, 49, + 60, 42, 235, 36, 128, 141, 73, 231, 136, 198, 190, 133, 16, 114, 234, 61, 17, 89, 88, 113, + 2, 207, 222, 104, 227, 236, 11, 239, 193, 58, 92, 13, 189, 158, 162, 62, 249, 200, 140, 98, + 120, 84, 213, 72, 256, 25, 146, 205, 15, 139, 123, 9, 32, 228, 211, 122, 34, 178, 176, 226, + 4, 157, 187, 208, 197, 215, 22, 221, 129, 116, 184, 26, 121, 59, 67, 124, 241, 143, 23, 196, + 240, 168, 169, 144, 255, 50, 35, 153, 30, 21, 246, 18, 64, 199, 165, 244, 68, 99, 95, 195, + 8, 57, 117, 159, 137, 173, 44, 185, 1, 232, 111, 52, 242, 118, 134, 248, 225, 29, 46, 135, + 223, 79, 81, 31, 253, 100, 70, 49, 60, 42, 235, 36, 128, 141, 73, 231, 136, 198, 190, 133, + 16, 114, 234, 61, 17, 89, 88, 113, 2, 207, 222, 104, 227, 236, 11, 239, 193, 58, 92, 13, + 189, 158, 162, 62, 249, 200, 140, 98, 120, 84, 213, 72, 256, 25, 146, 205, 15, 139, 123, 9, + 32, 228, 211, 122, 34, 178, 176, 226, 4, 157, 187, 208, 197, 215, 22, 221, 129, 116, 184, + 26, 121, 59, 67, 124, 241, 143, 23, 196, 240, 168, 169, 144, 255, 50, 35, 153, 30, 21, 246, + 18, 64, 199, 165, 244, 68, 99, 95, 195, 8, 57, 117, 159, 137, 173, 44, 185, 1, + ], + [ + 1, 233, 62, 54, 246, 7, 89, 177, 121, 180, 49, 109, 211, 76, 232, 86, 249, 192, 18, 82, 88, + 201, 59, 126, 60, 102, 122, 156, 111, 163, 200, 83, 64, 6, 113, 115, 67, 191, 42, 20, 34, + 212, 52, 37, 140, 238, 199, 107, 2, 209, 124, 108, 235, 14, 178, 97, 242, 103, 98, 218, 165, + 152, 207, 172, 241, 127, 36, 164, 176, 145, 118, 252, 120, 204, 244, 55, 222, 69, 143, 166, + 128, 12, 226, 230, 134, 125, 84, 40, 68, 167, 104, 74, 23, 219, 141, 214, 4, 161, 248, 216, + 213, 28, 99, 194, 227, 206, 196, 179, 73, 47, 157, 87, 225, 254, 72, 71, 95, 33, 236, 247, + 240, 151, 231, 110, 187, 138, 29, 75, 256, 24, 195, 203, 11, 250, 168, 80, 136, 77, 208, + 148, 46, 181, 25, 171, 8, 65, 239, 175, 169, 56, 198, 131, 197, 155, 135, 101, 146, 94, 57, + 174, 193, 251, 144, 142, 190, 66, 215, 237, 223, 45, 205, 220, 117, 19, 58, 150, 255, 48, + 133, 149, 22, 243, 79, 160, 15, 154, 159, 39, 92, 105, 50, 85, 16, 130, 221, 93, 81, 112, + 139, 5, 137, 53, 13, 202, 35, 188, 114, 91, 129, 245, 31, 27, 123, 132, 173, 217, 189, 90, + 153, 183, 234, 38, 116, 43, 253, 96, 9, 41, 44, 229, 158, 63, 30, 51, 61, 78, 184, 210, 100, + 170, 32, 3, 185, 186, 162, 224, 21, 10, 17, 106, 26, 147, 70, 119, 228, 182, 1, + ], + [ + 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, 146, 240, 134, + 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, + 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, + 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, 121, 44, 16, + 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, 242, 88, 32, + 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, 227, 176, 64, + 70, 189, 22, 8, 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, 95, 128, 140, + 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, 190, 256, 23, + 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, 123, 255, 46, + 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1, 234, 15, 169, 225, 222, 34, 246, 253, 92, 197, + 95, 128, 140, 121, 44, 16, 146, 240, 134, 2, 211, 30, 81, 193, 187, 68, 235, 249, 184, 137, + 190, 256, 23, 242, 88, 32, 35, 223, 11, 4, 165, 60, 162, 129, 117, 136, 213, 241, 111, 17, + 123, 255, 46, 227, 176, 64, 70, 189, 22, 8, 73, 120, 67, 1, + ], + [ + 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, + 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, + 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, + 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, 190, 189, 211, + 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, 256, 22, 30, + 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, 81, 17, 140, 4, + 169, 137, 70, 2, 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, 123, 121, 165, 225, + 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, 255, 44, 60, 222, + 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, 162, 34, 23, 8, + 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1, 235, 227, 146, 129, 246, 242, 73, 193, + 123, 121, 165, 225, 190, 189, 211, 241, 95, 223, 234, 249, 176, 240, 117, 253, 88, 120, 187, + 255, 44, 60, 222, 256, 22, 30, 111, 128, 11, 15, 184, 64, 134, 136, 92, 32, 67, 68, 46, 16, + 162, 34, 23, 8, 81, 17, 140, 4, 169, 137, 70, 2, 213, 197, 35, 1, + ], + [ + 1, 236, 184, 248, 189, 143, 81, 98, 255, 42, 146, 18, 136, 228, 95, 61, 4, 173, 222, 221, + 242, 58, 67, 135, 249, 168, 70, 72, 30, 141, 123, 244, 16, 178, 117, 113, 197, 232, 11, 26, + 225, 158, 23, 31, 120, 50, 235, 205, 64, 198, 211, 195, 17, 157, 44, 104, 129, 118, 92, 124, + 223, 200, 169, 49, 256, 21, 73, 9, 68, 114, 176, 159, 2, 215, 111, 239, 121, 29, 162, 196, + 253, 84, 35, 36, 15, 199, 190, 122, 8, 89, 187, 185, 227, 116, 134, 13, 241, 79, 140, 144, + 60, 25, 246, 231, 32, 99, 234, 226, 137, 207, 22, 52, 193, 59, 46, 62, 240, 100, 213, 153, + 128, 139, 165, 133, 34, 57, 88, 208, 1, 236, 184, 248, 189, 143, 81, 98, 255, 42, 146, 18, + 136, 228, 95, 61, 4, 173, 222, 221, 242, 58, 67, 135, 249, 168, 70, 72, 30, 141, 123, 244, + 16, 178, 117, 113, 197, 232, 11, 26, 225, 158, 23, 31, 120, 50, 235, 205, 64, 198, 211, 195, + 17, 157, 44, 104, 129, 118, 92, 124, 223, 200, 169, 49, 256, 21, 73, 9, 68, 114, 176, 159, + 2, 215, 111, 239, 121, 29, 162, 196, 253, 84, 35, 36, 15, 199, 190, 122, 8, 89, 187, 185, + 227, 116, 134, 13, 241, 79, 140, 144, 60, 25, 246, 231, 32, 99, 234, 226, 137, 207, 22, 52, + 193, 59, 46, 62, 240, 100, 213, 153, 128, 139, 165, 133, 34, 57, 88, 208, 1, + ], + [ + 1, 237, 143, 224, 146, 164, 61, 65, 242, 43, 168, 238, 123, 110, 113, 53, 225, 126, 50, 28, + 211, 149, 104, 233, 223, 166, 21, 94, 176, 78, 239, 103, 253, 80, 199, 132, 187, 115, 13, + 254, 60, 85, 99, 76, 22, 74, 62, 45, 128, 10, 57, 145, 184, 175, 98, 96, 136, 107, 173, 138, + 67, 202, 72, 102, 16, 194, 232, 243, 23, 54, 205, 12, 17, 174, 118, 210, 169, 218, 9, 77, 2, + 217, 29, 191, 35, 71, 122, 130, 227, 86, 79, 219, 246, 220, 226, 106, 193, 252, 100, 56, + 165, 41, 208, 209, 189, 75, 42, 188, 95, 156, 221, 206, 249, 160, 141, 7, 117, 230, 26, 251, + 120, 170, 198, 152, 44, 148, 124, 90, 256, 20, 114, 33, 111, 93, 196, 192, 15, 214, 89, 19, + 134, 147, 144, 204, 32, 131, 207, 229, 46, 108, 153, 24, 34, 91, 236, 163, 81, 179, 18, 154, + 4, 177, 58, 125, 70, 142, 244, 3, 197, 172, 158, 181, 235, 183, 195, 212, 129, 247, 200, + 112, 73, 82, 159, 161, 121, 150, 84, 119, 190, 55, 185, 155, 241, 63, 25, 14, 234, 203, 52, + 245, 240, 83, 139, 47, 88, 39, 248, 180, 255, 40, 228, 66, 222, 186, 135, 127, 30, 171, 178, + 38, 11, 37, 31, 151, 64, 5, 157, 201, 92, 216, 49, 48, 68, 182, 215, 69, 162, 101, 36, 51, + 8, 97, 116, 250, 140, 27, 231, 6, 137, 87, 59, 105, 213, 109, 133, 167, 1, + ], + [ + 1, 238, 104, 80, 22, 96, 232, 218, 227, 56, 221, 170, 111, 204, 236, 142, 129, 119, 52, 40, + 11, 48, 116, 109, 242, 28, 239, 85, 184, 102, 118, 71, 193, 188, 26, 20, 134, 24, 58, 183, + 121, 14, 248, 171, 92, 51, 59, 164, 225, 94, 13, 10, 67, 12, 29, 220, 189, 7, 124, 214, 46, + 154, 158, 82, 241, 47, 135, 5, 162, 6, 143, 110, 223, 132, 62, 107, 23, 77, 79, 41, 249, + 152, 196, 131, 81, 3, 200, 55, 240, 66, 31, 182, 140, 167, 168, 149, 253, 76, 98, 194, 169, + 130, 100, 156, 120, 33, 144, 91, 70, 212, 84, 203, 255, 38, 49, 97, 213, 65, 50, 78, 60, + 145, 72, 174, 35, 106, 42, 230, 256, 19, 153, 177, 235, 161, 25, 39, 30, 201, 36, 87, 146, + 53, 21, 115, 128, 138, 205, 217, 246, 209, 141, 148, 15, 229, 18, 172, 73, 155, 139, 186, + 64, 69, 231, 237, 123, 233, 199, 74, 136, 243, 9, 86, 165, 206, 198, 93, 32, 163, 244, 247, + 190, 245, 228, 37, 68, 250, 133, 43, 211, 103, 99, 175, 16, 210, 122, 252, 95, 251, 114, + 147, 34, 125, 195, 150, 234, 180, 178, 216, 8, 105, 61, 126, 176, 254, 57, 202, 17, 191, + 226, 75, 117, 90, 89, 108, 4, 181, 159, 63, 88, 127, 157, 101, 137, 224, 113, 166, 187, 45, + 173, 54, 2, 219, 208, 160, 44, 192, 207, 179, 197, 112, 185, 83, 222, 151, 215, 27, 1, + ], + [ + 1, 239, 67, 79, 120, 153, 73, 228, 8, 113, 22, 118, 189, 196, 70, 25, 64, 133, 176, 173, + 227, 26, 46, 200, 255, 36, 123, 99, 17, 208, 111, 58, 241, 31, 213, 21, 136, 122, 117, 207, + 129, 248, 162, 168, 60, 205, 165, 114, 4, 185, 11, 59, 223, 98, 35, 141, 32, 195, 88, 215, + 242, 13, 23, 100, 256, 18, 190, 178, 137, 104, 184, 29, 249, 144, 235, 139, 68, 61, 187, + 232, 193, 124, 81, 84, 30, 231, 211, 57, 2, 221, 134, 158, 240, 49, 146, 199, 16, 226, 44, + 236, 121, 135, 140, 50, 128, 9, 95, 89, 197, 52, 92, 143, 253, 72, 246, 198, 34, 159, 222, + 116, 225, 62, 169, 42, 15, 244, 234, 157, 1, 239, 67, 79, 120, 153, 73, 228, 8, 113, 22, + 118, 189, 196, 70, 25, 64, 133, 176, 173, 227, 26, 46, 200, 255, 36, 123, 99, 17, 208, 111, + 58, 241, 31, 213, 21, 136, 122, 117, 207, 129, 248, 162, 168, 60, 205, 165, 114, 4, 185, 11, + 59, 223, 98, 35, 141, 32, 195, 88, 215, 242, 13, 23, 100, 256, 18, 190, 178, 137, 104, 184, + 29, 249, 144, 235, 139, 68, 61, 187, 232, 193, 124, 81, 84, 30, 231, 211, 57, 2, 221, 134, + 158, 240, 49, 146, 199, 16, 226, 44, 236, 121, 135, 140, 50, 128, 9, 95, 89, 197, 52, 92, + 143, 253, 72, 246, 198, 34, 159, 222, 116, 225, 62, 169, 42, 15, 244, 234, 157, 1, + ], + [ + 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, + 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, + 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, + 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, + 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, + 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, + 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, + 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, + 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, + 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, + 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, + 1, 240, 32, 227, 253, 68, 129, 120, 16, 242, 255, 34, 193, 60, 8, 121, 256, 17, 225, 30, 4, + 189, 128, 137, 241, 15, 2, 223, 64, 197, 249, 136, 1, + ], + [ + 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, + 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, + 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, + 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, + 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, + 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, + 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, + 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, + 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, + 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, + 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, + 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, 241, 256, 16, 1, + ], + [ + 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, + 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, + 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, + 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, + 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, + 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, + 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, + 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, + 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, + 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, + 189, 249, 120, 256, 15, 32, 34, 4, 197, 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, 242, + 225, 223, 253, 60, 128, 136, 16, 17, 2, 227, 193, 189, 249, 120, 256, 15, 32, 34, 4, 197, + 129, 121, 241, 240, 255, 30, 64, 68, 8, 137, 1, + ], + [ + 1, 243, 196, 83, 123, 77, 207, 186, 223, 219, 18, 5, 187, 209, 158, 101, 128, 7, 159, 87, + 67, 90, 25, 164, 17, 19, 248, 126, 35, 24, 178, 78, 193, 125, 49, 85, 95, 212, 116, 175, + 120, 119, 133, 194, 111, 245, 168, 218, 32, 66, 104, 86, 81, 151, 199, 41, 197, 69, 62, 160, + 73, 6, 173, 148, 241, 224, 205, 214, 88, 53, 29, 108, 30, 94, 226, 177, 92, 254, 42, 183, 8, + 145, 26, 150, 213, 102, 114, 203, 242, 210, 144, 40, 211, 130, 236, 37, 253, 56, 244, 182, + 22, 206, 200, 27, 136, 152, 185, 237, 23, 192, 139, 110, 2, 229, 135, 166, 246, 154, 157, + 115, 189, 181, 36, 10, 117, 161, 59, 202, 256, 14, 61, 174, 134, 180, 50, 71, 34, 38, 239, + 252, 70, 48, 99, 156, 129, 250, 98, 170, 190, 167, 232, 93, 240, 238, 9, 131, 222, 233, 79, + 179, 64, 132, 208, 172, 162, 45, 141, 82, 137, 138, 124, 63, 146, 12, 89, 39, 225, 191, 153, + 171, 176, 106, 58, 216, 60, 188, 195, 97, 184, 251, 84, 109, 16, 33, 52, 43, 169, 204, 228, + 149, 227, 163, 31, 80, 165, 3, 215, 74, 249, 112, 231, 107, 44, 155, 143, 54, 15, 47, 113, + 217, 46, 127, 21, 220, 4, 201, 13, 75, 235, 51, 57, 230, 121, 105, 72, 20, 234, 65, 118, + 147, 255, 28, 122, 91, 11, 103, 100, 142, 68, 76, 221, 247, 140, 96, 198, 55, 1, + ], + [ + 1, 244, 169, 116, 34, 72, 92, 89, 128, 135, 44, 199, 240, 221, 211, 84, 193, 61, 235, 29, + 137, 18, 23, 215, 32, 98, 11, 114, 60, 248, 117, 21, 241, 208, 123, 200, 227, 133, 70, 118, + 8, 153, 67, 157, 15, 62, 222, 198, 253, 52, 95, 50, 121, 226, 146, 158, 2, 231, 81, 232, 68, + 144, 184, 178, 256, 13, 88, 141, 223, 185, 165, 168, 129, 122, 213, 58, 17, 36, 46, 173, 64, + 196, 22, 228, 120, 239, 234, 42, 225, 159, 246, 143, 197, 9, 140, 236, 16, 49, 134, 57, 30, + 124, 187, 139, 249, 104, 190, 100, 242, 195, 35, 59, 4, 205, 162, 207, 136, 31, 111, 99, + 255, 26, 176, 25, 189, 113, 73, 79, 1, 244, 169, 116, 34, 72, 92, 89, 128, 135, 44, 199, + 240, 221, 211, 84, 193, 61, 235, 29, 137, 18, 23, 215, 32, 98, 11, 114, 60, 248, 117, 21, + 241, 208, 123, 200, 227, 133, 70, 118, 8, 153, 67, 157, 15, 62, 222, 198, 253, 52, 95, 50, + 121, 226, 146, 158, 2, 231, 81, 232, 68, 144, 184, 178, 256, 13, 88, 141, 223, 185, 165, + 168, 129, 122, 213, 58, 17, 36, 46, 173, 64, 196, 22, 228, 120, 239, 234, 42, 225, 159, 246, + 143, 197, 9, 140, 236, 16, 49, 134, 57, 30, 124, 187, 139, 249, 104, 190, 100, 242, 195, 35, + 59, 4, 205, 162, 207, 136, 31, 111, 99, 255, 26, 176, 25, 189, 113, 73, 79, 1, + ], + [ + 1, 245, 144, 71, 176, 201, 158, 160, 136, 167, 52, 147, 35, 94, 157, 172, 249, 96, 133, 203, + 134, 191, 21, 5, 197, 206, 98, 109, 234, 19, 29, 166, 64, 3, 221, 175, 213, 14, 89, 217, + 223, 151, 244, 156, 184, 105, 25, 214, 2, 233, 31, 142, 95, 145, 59, 63, 15, 77, 104, 37, + 70, 188, 57, 87, 241, 192, 9, 149, 11, 125, 42, 10, 137, 155, 196, 218, 211, 38, 58, 75, + 128, 6, 185, 93, 169, 28, 178, 177, 189, 45, 231, 55, 111, 210, 50, 171, 4, 209, 62, 27, + 190, 33, 118, 126, 30, 154, 208, 74, 140, 119, 114, 174, 225, 127, 18, 41, 22, 250, 84, 20, + 17, 53, 135, 179, 165, 76, 116, 150, 256, 12, 113, 186, 81, 56, 99, 97, 121, 90, 205, 110, + 222, 163, 100, 85, 8, 161, 124, 54, 123, 66, 236, 252, 60, 51, 159, 148, 23, 238, 228, 91, + 193, 254, 36, 82, 44, 243, 168, 40, 34, 106, 13, 101, 73, 152, 232, 43, 255, 24, 226, 115, + 162, 112, 198, 194, 242, 180, 153, 220, 187, 69, 200, 170, 16, 65, 248, 108, 246, 132, 215, + 247, 120, 102, 61, 39, 46, 219, 199, 182, 129, 251, 72, 164, 88, 229, 79, 80, 68, 212, 26, + 202, 146, 47, 207, 86, 253, 48, 195, 230, 67, 224, 139, 131, 227, 103, 49, 183, 117, 138, + 143, 83, 32, 130, 239, 216, 235, 7, 173, 237, 240, 204, 122, 78, 92, 181, 141, 107, 1, + ], + [ + 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, + 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, + 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, + 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, 235, 242, 165, 241, + 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, 256, 11, 136, 46, 8, + 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, 129, 123, 189, 234, + 253, 44, 30, 184, 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, 64, 67, 34, 140, 2, + 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, 225, 95, 240, 187, + 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, 16, 81, 137, 35, + 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1, 246, 121, 211, 249, 88, 60, 111, + 64, 67, 34, 140, 2, 235, 242, 165, 241, 176, 120, 222, 128, 134, 68, 23, 4, 213, 227, 73, + 225, 95, 240, 187, 256, 11, 136, 46, 8, 169, 197, 146, 193, 190, 223, 117, 255, 22, 15, 92, + 16, 81, 137, 35, 129, 123, 189, 234, 253, 44, 30, 184, 32, 162, 17, 70, 1, + ], + [ + 1, 247, 100, 28, 234, 230, 13, 127, 15, 107, 215, 163, 169, 109, 195, 106, 225, 63, 141, + 132, 222, 93, 98, 48, 34, 174, 59, 181, 246, 110, 185, 206, 253, 40, 114, 145, 92, 108, 205, + 6, 197, 86, 168, 119, 95, 78, 248, 90, 128, 5, 207, 243, 140, 142, 122, 65, 121, 75, 21, 47, + 44, 74, 31, 204, 16, 97, 58, 191, 146, 82, 208, 233, 240, 170, 99, 38, 134, 202, 36, 154, 2, + 237, 200, 56, 211, 203, 26, 254, 30, 214, 173, 69, 81, 218, 133, 212, 193, 126, 25, 7, 187, + 186, 196, 96, 68, 91, 118, 105, 235, 220, 113, 155, 249, 80, 228, 33, 184, 216, 153, 12, + 137, 172, 79, 238, 190, 156, 239, 180, 256, 10, 157, 229, 23, 27, 244, 130, 242, 150, 42, + 94, 88, 148, 62, 151, 32, 194, 116, 125, 35, 164, 159, 209, 223, 83, 198, 76, 11, 147, 72, + 51, 4, 217, 143, 112, 165, 149, 52, 251, 60, 171, 89, 138, 162, 179, 9, 167, 129, 252, 50, + 14, 117, 115, 135, 192, 136, 182, 236, 210, 213, 183, 226, 53, 241, 160, 199, 66, 111, 175, + 49, 24, 17, 87, 158, 219, 123, 55, 221, 103, 255, 20, 57, 201, 46, 54, 231, 3, 227, 43, 84, + 188, 176, 39, 124, 45, 64, 131, 232, 250, 70, 71, 61, 161, 189, 166, 139, 152, 22, 37, 144, + 102, 8, 177, 29, 224, 73, 41, 104, 245, 120, 85, 178, 19, 67, 101, 18, 77, 1, + ], + [ + 1, 248, 81, 42, 136, 61, 222, 58, 249, 72, 123, 178, 197, 26, 23, 50, 64, 195, 44, 118, 223, + 49, 73, 114, 2, 239, 162, 84, 15, 122, 187, 116, 241, 144, 246, 99, 137, 52, 46, 100, 128, + 133, 88, 236, 189, 98, 146, 228, 4, 221, 67, 168, 30, 244, 117, 232, 225, 31, 235, 198, 17, + 104, 92, 200, 256, 9, 176, 215, 121, 196, 35, 199, 8, 185, 134, 79, 60, 231, 234, 207, 193, + 62, 213, 139, 34, 208, 184, 143, 255, 18, 95, 173, 242, 135, 70, 141, 16, 113, 11, 158, 120, + 205, 211, 157, 129, 124, 169, 21, 68, 159, 111, 29, 253, 36, 190, 89, 227, 13, 140, 25, 32, + 226, 22, 59, 240, 153, 165, 57, 1, 248, 81, 42, 136, 61, 222, 58, 249, 72, 123, 178, 197, + 26, 23, 50, 64, 195, 44, 118, 223, 49, 73, 114, 2, 239, 162, 84, 15, 122, 187, 116, 241, + 144, 246, 99, 137, 52, 46, 100, 128, 133, 88, 236, 189, 98, 146, 228, 4, 221, 67, 168, 30, + 244, 117, 232, 225, 31, 235, 198, 17, 104, 92, 200, 256, 9, 176, 215, 121, 196, 35, 199, 8, + 185, 134, 79, 60, 231, 234, 207, 193, 62, 213, 139, 34, 208, 184, 143, 255, 18, 95, 173, + 242, 135, 70, 141, 16, 113, 11, 158, 120, 205, 211, 157, 129, 124, 169, 21, 68, 159, 111, + 29, 253, 36, 190, 89, 227, 13, 140, 25, 32, 226, 22, 59, 240, 153, 165, 57, 1, + ], + [ + 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, + 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, + 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, + 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, + 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, + 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, + 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, + 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, + 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, + 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, + 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, + 193, 255, 16, 129, 253, 32, 1, 249, 64, 2, 241, 128, 4, 225, 256, 8, 193, 255, 16, 129, 253, + 32, 1, + ], + [ + 1, 250, 49, 171, 88, 155, 200, 142, 34, 19, 124, 160, 165, 130, 118, 202, 128, 132, 104, 43, + 213, 51, 157, 186, 240, 119, 195, 177, 46, 192, 198, 156, 193, 191, 205, 107, 22, 103, 50, + 164, 137, 69, 31, 40, 234, 161, 158, 179, 32, 33, 26, 75, 246, 77, 232, 175, 60, 94, 113, + 237, 140, 48, 178, 39, 241, 112, 244, 91, 134, 90, 141, 41, 227, 210, 72, 10, 187, 233, 168, + 109, 8, 201, 135, 83, 190, 212, 58, 108, 15, 152, 221, 252, 35, 12, 173, 74, 253, 28, 61, + 87, 162, 151, 228, 203, 121, 181, 18, 131, 111, 251, 42, 220, 2, 243, 98, 85, 176, 53, 143, + 27, 68, 38, 248, 63, 73, 3, 236, 147, 256, 7, 208, 86, 169, 102, 57, 115, 223, 238, 133, 97, + 92, 127, 139, 55, 129, 125, 153, 214, 44, 206, 100, 71, 17, 138, 62, 80, 211, 65, 59, 101, + 64, 66, 52, 150, 235, 154, 207, 93, 120, 188, 226, 217, 23, 96, 99, 78, 225, 224, 231, 182, + 11, 180, 25, 82, 197, 163, 144, 20, 117, 209, 79, 218, 16, 145, 13, 166, 123, 167, 116, 216, + 30, 47, 185, 247, 70, 24, 89, 148, 249, 56, 122, 174, 67, 45, 199, 149, 242, 105, 36, 5, + 222, 245, 84, 183, 4, 229, 196, 170, 95, 106, 29, 54, 136, 76, 239, 126, 146, 6, 215, 37, + 255, 14, 159, 172, 81, 204, 114, 230, 189, 219, 9, 194, 184, 254, 21, 110, 1, + ], + [ + 1, 251, 36, 41, 11, 191, 139, 194, 121, 45, 244, 78, 46, 238, 114, 87, 249, 48, 226, 186, + 169, 14, 173, 247, 60, 154, 104, 147, 146, 152, 116, 75, 64, 130, 248, 54, 190, 145, 158, + 80, 34, 53, 196, 109, 117, 69, 100, 171, 2, 245, 72, 82, 22, 125, 21, 131, 242, 90, 231, + 156, 92, 219, 228, 174, 241, 96, 195, 115, 81, 28, 89, 237, 120, 51, 208, 37, 35, 47, 232, + 150, 128, 3, 239, 108, 123, 33, 59, 160, 68, 106, 135, 218, 234, 138, 200, 85, 4, 233, 144, + 164, 44, 250, 42, 5, 227, 180, 205, 55, 184, 181, 199, 91, 225, 192, 133, 230, 162, 56, 178, + 217, 240, 102, 159, 74, 70, 94, 207, 43, 256, 6, 221, 216, 246, 66, 118, 63, 136, 212, 13, + 179, 211, 19, 143, 170, 8, 209, 31, 71, 88, 243, 84, 10, 197, 103, 153, 110, 111, 105, 141, + 182, 193, 127, 9, 203, 67, 112, 99, 177, 223, 204, 61, 148, 140, 188, 157, 86, 255, 12, 185, + 175, 235, 132, 236, 126, 15, 167, 26, 101, 165, 38, 29, 83, 16, 161, 62, 142, 176, 229, 168, + 20, 137, 206, 49, 220, 222, 210, 25, 107, 129, 254, 18, 149, 134, 224, 198, 97, 189, 151, + 122, 39, 23, 119, 57, 172, 253, 24, 113, 93, 213, 7, 215, 252, 30, 77, 52, 202, 73, 76, 58, + 166, 32, 65, 124, 27, 95, 201, 79, 40, 17, 155, 98, 183, 187, 163, 50, 214, 1, + ], + [ + 1, 252, 25, 132, 111, 216, 205, 3, 242, 75, 139, 76, 134, 101, 9, 212, 225, 160, 228, 145, + 46, 27, 122, 161, 223, 170, 178, 138, 81, 109, 226, 155, 253, 20, 157, 243, 70, 164, 208, + 245, 60, 214, 215, 210, 235, 110, 221, 180, 128, 131, 116, 191, 73, 149, 26, 127, 136, 91, + 59, 219, 190, 78, 124, 151, 16, 177, 143, 56, 234, 115, 196, 48, 17, 172, 168, 188, 88, 74, + 144, 51, 2, 247, 50, 7, 222, 175, 153, 6, 227, 150, 21, 152, 11, 202, 18, 167, 193, 63, 199, + 33, 92, 54, 244, 65, 189, 83, 99, 19, 162, 218, 195, 53, 249, 40, 57, 229, 140, 71, 159, + 233, 120, 171, 173, 163, 213, 220, 185, 103, 256, 5, 232, 125, 146, 41, 52, 254, 15, 182, + 118, 181, 123, 156, 248, 45, 32, 97, 29, 112, 211, 230, 135, 96, 34, 87, 79, 119, 176, 148, + 31, 102, 4, 237, 100, 14, 187, 93, 49, 12, 197, 43, 42, 47, 22, 147, 36, 77, 129, 126, 141, + 66, 184, 108, 231, 130, 121, 166, 198, 38, 67, 179, 133, 106, 241, 80, 114, 201, 23, 142, + 61, 209, 240, 85, 89, 69, 169, 183, 113, 206, 255, 10, 207, 250, 35, 82, 104, 251, 30, 107, + 236, 105, 246, 55, 239, 90, 64, 194, 58, 224, 165, 203, 13, 192, 68, 174, 158, 238, 95, 39, + 62, 204, 8, 217, 200, 28, 117, 186, 98, 24, 137, 86, 84, 94, 44, 37, 72, 154, 1, + ], + [ + 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, + 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, + 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, + 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, + 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, + 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, + 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, + 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, + 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, + 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, + 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, + 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, 253, 16, 193, 256, 4, 241, 64, 1, + ], + [ + 1, 254, 9, 230, 81, 14, 215, 126, 136, 106, 196, 183, 222, 105, 199, 174, 249, 24, 185, 216, + 123, 145, 79, 20, 197, 180, 231, 78, 23, 188, 207, 150, 64, 65, 62, 71, 44, 125, 139, 97, + 223, 102, 208, 147, 73, 38, 143, 85, 2, 251, 18, 203, 162, 28, 173, 252, 15, 212, 135, 109, + 187, 210, 141, 91, 241, 48, 113, 175, 246, 33, 158, 40, 137, 103, 205, 156, 46, 119, 157, + 43, 128, 130, 124, 142, 88, 250, 21, 194, 189, 204, 159, 37, 146, 76, 29, 170, 4, 245, 36, + 149, 67, 56, 89, 247, 30, 167, 13, 218, 117, 163, 25, 182, 225, 96, 226, 93, 235, 66, 59, + 80, 17, 206, 153, 55, 92, 238, 57, 86, 256, 3, 248, 27, 176, 243, 42, 131, 121, 151, 61, 74, + 35, 152, 58, 83, 8, 233, 72, 41, 134, 112, 178, 237, 60, 77, 26, 179, 234, 69, 50, 107, 193, + 192, 195, 186, 213, 132, 118, 160, 34, 155, 49, 110, 184, 219, 114, 172, 255, 6, 239, 54, + 95, 229, 84, 5, 242, 45, 122, 148, 70, 47, 116, 166, 16, 209, 144, 82, 11, 224, 99, 217, + 120, 154, 52, 101, 211, 138, 100, 214, 129, 127, 133, 115, 169, 7, 236, 63, 68, 53, 98, 220, + 111, 181, 228, 87, 253, 12, 221, 108, 190, 201, 168, 10, 227, 90, 244, 39, 140, 94, 232, 75, + 32, 161, 31, 164, 22, 191, 198, 177, 240, 51, 104, 202, 165, 19, 200, 171, 1, + ], + [ + 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, + 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, + 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, + 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, + 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, + 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, + 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, + 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, + 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, + 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, + 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, + 129, 256, 2, 253, 8, 241, 32, 193, 128, 1, 255, 4, 249, 16, 225, 64, 129, 256, 2, 253, 8, + 241, 32, 193, 128, 1, + ], + [ + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, + 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, 256, 1, + 256, 1, 256, 1, + ], +]; diff --git a/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/main.nr b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/main.nr new file mode 100644 index 00000000000..c55a6ac01e9 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/global_var_regression_entry_points/src/main.nr @@ -0,0 +1,60 @@ +mod consts; +use consts::EXPONENTIATE; + +fn main(x: Field, y: pub Field) { + /// Safety: testing context + unsafe { + assert(entry_point_only_const_global(x) == 2); + check_acc_entry_point(x, y); + assert(entry_point_only_const_global(x) == 2); + entry_point_inner_func_globals(x as Field, y); + // NOTE: We want a lot of these calls to display clearly + // that execution time has not been tainted by accidentally initializing globals + // for entry points which do not use them. + assert(entry_point_no_globals(x, y) == 1); + assert(entry_point_no_globals(x, y) == 1); + assert(entry_point_only_const_global(x) == 2); + assert(entry_point_only_const_global(x) == 2); + assert(entry_point_only_const_global(x) == 2); + assert(entry_point_only_const_global(x) == 2); + assert(entry_point_only_const_global(x) == 2); + assert(entry_point_no_globals(x, y) == 1); + assert(entry_point_no_globals(x, y) == 1); + assert(entry_point_no_globals(x, y) == 1); + } +} + +unconstrained fn check_acc_entry_point(x: Field, y: Field) { + let mut acc: Field = 0; + for i in 0..2 { + for j in 0..2 { + acc += EXPONENTIATE[i][j]; + } + } + assert(!acc.lt(x)); + assert(x != y); + + assert(inner(x + 1) == 2); +} + +fn inner(x: Field) -> Field { + x + 1 +} + +unconstrained fn entry_point_only_const_global(x: Field) -> Field { + inner(x + 1) +} + +unconstrained fn entry_point_no_globals(x: Field, y: Field) -> Field { + x + y +} + +unconstrained fn entry_point_inner_func_globals(x: Field, y: Field) { + one_more_wrapper(x, y); +} + +unconstrained fn one_more_wrapper(x: Field, y: Field) { + check_acc_entry_point(x, y); + check_acc_entry_point(x, y); + check_acc_entry_point(x, y); +} diff --git a/noir/noir-repo/test_programs/execution_success/reference_only_used_as_alias/src/main.nr b/noir/noir-repo/test_programs/execution_success/reference_only_used_as_alias/src/main.nr index 21000d90699..3bbf1cf9ccb 100644 --- a/noir/noir-repo/test_programs/execution_success/reference_only_used_as_alias/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/reference_only_used_as_alias/src/main.nr @@ -63,7 +63,6 @@ where |e: Event| { /// Safety: testing context unsafe { - //@safety: testing context func(context.a); } emit_with_keys(context, randomness, e, compute); diff --git a/noir/noir-repo/test_programs/execution_success/u16_support/src/main.nr b/noir/noir-repo/test_programs/execution_success/u16_support/src/main.nr index 05d90f7e8aa..d86ad348708 100644 --- a/noir/noir-repo/test_programs/execution_success/u16_support/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/u16_support/src/main.nr @@ -2,7 +2,6 @@ fn main(x: u16) { test_u16(x); /// Safety: testing context unsafe { - //@safety: testing context test_u16_unconstrained(x); } } diff --git a/noir/noir-repo/test_programs/gates_report.sh b/noir/noir-repo/test_programs/gates_report.sh index c92346f40e8..8d0646ac689 100755 --- a/noir/noir-repo/test_programs/gates_report.sh +++ b/noir/noir-repo/test_programs/gates_report.sh @@ -4,7 +4,7 @@ set -e BACKEND=${BACKEND:-bb} # These tests are incompatible with gas reporting -excluded_dirs=("workspace" "workspace_default_member" "databus" "double_verify_honk_proof" "verify_honk_proof") +excluded_dirs=("workspace" "workspace_default_member" "databus" "double_verify_honk_proof" "verify_honk_proof" "verify_rollup_honk_proof") current_dir=$(pwd) artifacts_path="$current_dir/acir_artifacts" diff --git a/noir/noir-repo/test_programs/memory_report.sh b/noir/noir-repo/test_programs/memory_report.sh index 4ba7579b390..00065fbfb36 100755 --- a/noir/noir-repo/test_programs/memory_report.sh +++ b/noir/noir-repo/test_programs/memory_report.sh @@ -8,7 +8,7 @@ PARSE_MEMORY=$(realpath "$(dirname "$0")/parse_memory.sh") # Tests to be profiled for memory report -tests_to_profile=("keccak256" "workspace" "regression_4709" "ram_blowup_regression") +tests_to_profile=("keccak256" "workspace" "regression_4709" "ram_blowup_regression" "global_var_regression_entry_points") current_dir=$(pwd) base_path="$current_dir/execution_success" diff --git a/noir/noir-repo/test_programs/noir_test_success/brillig_oracle/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/brillig_oracle/src/main.nr index d9ab64edd52..77dbeef9aa1 100644 --- a/noir/noir-repo/test_programs/noir_test_success/brillig_oracle/src/main.nr +++ b/noir/noir-repo/test_programs/noir_test_success/brillig_oracle/src/main.nr @@ -10,7 +10,6 @@ fn test_main() { fn main(_x: Field) { /// Safety: testing context unsafe { - //@safety: testing context let size = 20; // TODO: Add a method along the lines of `(0..size).to_array()`. let mut mock_oracle_response = [0; 20]; diff --git a/noir/noir-repo/test_programs/noir_test_success/mock_oracle/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/mock_oracle/src/main.nr index 8daf84dd7b8..aaf2c87ddb0 100644 --- a/noir/noir-repo/test_programs/noir_test_success/mock_oracle/src/main.nr +++ b/noir/noir-repo/test_programs/noir_test_success/mock_oracle/src/main.nr @@ -36,7 +36,6 @@ unconstrained fn struct_field(point: Point, array: [Field; 4]) -> Field { fn test_mock_no_returns() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("void_field"); void_field(); // Some return value must be set } @@ -46,7 +45,6 @@ fn test_mock_no_returns() { fn test_mock() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("void_field").returns(10); assert_eq(void_field(), 10); } @@ -56,7 +54,6 @@ fn test_mock() { fn test_multiple_mock() { /// Safety: testing context unsafe { - //@safety: testing context let first_mock = OracleMock::mock("void_field").returns(10); OracleMock::mock("void_field").returns(42); @@ -72,7 +69,6 @@ fn test_multiple_mock() { fn test_multiple_mock_times() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("void_field").returns(10).times(2); OracleMock::mock("void_field").returns(42); @@ -86,7 +82,6 @@ fn test_multiple_mock_times() { fn test_mock_with_params() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("field_field").with_params((5,)).returns(10); assert_eq(field_field(5), 10); } @@ -96,7 +91,6 @@ fn test_mock_with_params() { fn test_multiple_mock_with_params() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("field_field").with_params((5,)).returns(10); OracleMock::mock("field_field").with_params((7,)).returns(14); @@ -109,7 +103,6 @@ fn test_multiple_mock_with_params() { fn test_mock_last_params() { /// Safety: testing context unsafe { - //@safety: testing context let mock = OracleMock::mock("field_field").returns(10); assert_eq(field_field(5), 10); @@ -121,7 +114,6 @@ fn test_mock_last_params() { fn test_mock_last_params_many_calls() { /// Safety: testing context unsafe { - //@safety: testing context let mock = OracleMock::mock("field_field").returns(10); assert_eq(field_field(5), 10); assert_eq(field_field(7), 10); @@ -139,7 +131,6 @@ fn test_mock_struct_field() { /// Safety: testing context unsafe { - //@safety: testing context OracleMock::mock("struct_field").returns(42).times(2); let timeless_mock = OracleMock::mock("struct_field").returns(0); assert_eq(42, struct_field(point, array)); diff --git a/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr index 90b4fc97081..05bc2a5ce13 100644 --- a/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr +++ b/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr @@ -18,7 +18,6 @@ fn test_acir() { fn test_brillig() { /// Safety: testing context unsafe { - //@safety: testing context assert_eq(out_of_bounds_unconstrained_wrapper([0; 50], [0; 50]), 0); } } diff --git a/noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr index 781d3e33ea3..01f358625be 100644 --- a/noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr +++ b/noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr @@ -3,6 +3,6 @@ #[test(should_fail_with = "attempt to add with overflow")] fn main() { - let var1: u8 = ((255 + 1) ^ (255 + 1)) - ((255 + 1) - (255 + 1)); - assert_eq(var1, 0); + let var1: u8 = ((255 + 1) ^ (255 + 1) ^ (255 + 1)); + assert_eq(var1 as Field, 256); } diff --git a/noir/noir-repo/tooling/lsp/src/lib.rs b/noir/noir-repo/tooling/lsp/src/lib.rs index 97a1c7ad27b..f8a4bd6b74a 100644 --- a/noir/noir-repo/tooling/lsp/src/lib.rs +++ b/noir/noir-repo/tooling/lsp/src/lib.rs @@ -215,7 +215,7 @@ fn get_package_tests_in_crate( let fm = &context.file_manager; let files = fm.as_file_map(); let tests = - context.get_all_test_functions_in_crate_matching(crate_id, FunctionNameMatch::Anything); + context.get_all_test_functions_in_crate_matching(crate_id, &FunctionNameMatch::Anything); let package_tests: Vec<_> = tests .into_iter() diff --git a/noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs b/noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs index 0c1877c156d..ab98ab8bf10 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs @@ -96,7 +96,7 @@ pub(crate) fn collect_lenses_for_package( let fm = &context.file_manager; let files = fm.as_file_map(); let tests = - context.get_all_test_functions_in_crate_matching(&crate_id, FunctionNameMatch::Anything); + context.get_all_test_functions_in_crate_matching(&crate_id, &FunctionNameMatch::Anything); for (func_name, test_function) in tests { let location = context.function_meta(&test_function.get_id()).name.location; let file_id = location.file; diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion.rs b/noir/noir-repo/tooling/lsp/src/requests/completion.rs index 0c51772935a..b464c3e7adc 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion.rs @@ -1,6 +1,7 @@ use std::{ collections::{BTreeMap, HashMap, HashSet}, future::{self, Future}, + ops::Deref, }; use async_lsp::ResponseError; @@ -199,15 +200,15 @@ impl<'a> NodeFinder<'a> { }; let location = Location::new(span, self.file); - let Some(ReferenceId::Type(struct_id)) = self.interner.find_referenced(location) else { + let Some(ReferenceId::Type(type_id)) = self.interner.find_referenced(location) else { return; }; - let struct_type = self.interner.get_type(struct_id); - let struct_type = struct_type.borrow(); + let data_type = self.interner.get_type(type_id); + let data_type = data_type.borrow(); // First get all of the struct's fields - let Some(fields) = struct_type.get_fields_as_written() else { + let Some(fields) = data_type.get_fields_as_written() else { return; }; @@ -223,7 +224,7 @@ impl<'a> NodeFinder<'a> { self.completion_items.push(self.struct_field_completion_item( &field.name.0.contents, &field.typ, - struct_type.id, + data_type.id, *field_index, self_prefix, )); @@ -320,10 +321,11 @@ impl<'a> NodeFinder<'a> { match module_def_id { ModuleDefId::ModuleId(id) => module_id = id, - ModuleDefId::TypeId(struct_id) => { - let struct_type = self.interner.get_type(struct_id); + ModuleDefId::TypeId(type_id) => { + let data_type = self.interner.get_type(type_id); + self.complete_enum_variants_without_parameters(&data_type.borrow(), &prefix); self.complete_type_methods( - &Type::DataType(struct_type, vec![]), + &Type::DataType(data_type, vec![]), &prefix, FunctionKind::Any, function_completion_kind, @@ -657,7 +659,7 @@ impl<'a> NodeFinder<'a> { return; }; - let struct_id = get_type_struct_id(typ); + let type_id = get_type_type_id(typ); let is_primitive = typ.is_primitive(); let has_self_param = matches!(function_kind, FunctionKind::SelfType(..)); @@ -669,15 +671,11 @@ impl<'a> NodeFinder<'a> { for (func_id, trait_id) in methods.find_matching_methods(typ, has_self_param, self.interner) { - if let Some(struct_id) = struct_id { + if let Some(type_id) = type_id { let modifiers = self.interner.function_modifiers(&func_id); let visibility = modifiers.visibility; - if !struct_member_is_visible( - struct_id, - visibility, - self.module_id, - self.def_maps, - ) { + if !struct_member_is_visible(type_id, visibility, self.module_id, self.def_maps) + { continue; } } @@ -801,6 +799,23 @@ impl<'a> NodeFinder<'a> { } } + fn complete_enum_variants_without_parameters(&mut self, data_type: &DataType, prefix: &str) { + let Some(variants) = data_type.get_variants_as_written() else { + return; + }; + + for (index, variant) in variants.iter().enumerate() { + // Variants with parameters are represented as functions and are suggested in `complete_type_methods` + if variant.is_function || !name_matches(&variant.name.0.contents, prefix) { + continue; + } + + let item = + self.enum_variant_completion_item(variant.name.to_string(), data_type.id, index); + self.completion_items.push(item); + } + } + fn complete_struct_fields( &mut self, struct_type: &DataType, @@ -1900,13 +1915,13 @@ fn get_array_element_type(typ: Type) -> Option { } } -fn get_type_struct_id(typ: &Type) -> Option { - match typ { +fn get_type_type_id(typ: &Type) -> Option { + match typ.follow_bindings_shallow().deref() { Type::DataType(struct_type, _) => Some(struct_type.borrow().id), Type::Alias(type_alias, generics) => { let type_alias = type_alias.borrow(); let typ = type_alias.get_type(generics); - get_type_struct_id(&typ) + get_type_type_id(&typ) } _ => None, } @@ -1958,7 +1973,7 @@ fn name_matches(name: &str, prefix: &str) -> bool { fn module_def_id_from_reference_id(reference_id: ReferenceId) -> Option { match reference_id { ReferenceId::Module(module_id) => Some(ModuleDefId::ModuleId(module_id)), - ReferenceId::Type(struct_id) => Some(ModuleDefId::TypeId(struct_id)), + ReferenceId::Type(type_id) => Some(ModuleDefId::TypeId(type_id)), ReferenceId::Trait(trait_id) => Some(ModuleDefId::TraitId(trait_id)), ReferenceId::Function(func_id) => Some(ModuleDefId::FunctionId(func_id)), ReferenceId::Alias(type_alias_id) => Some(ModuleDefId::TypeAliasId(type_alias_id)), diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs index 039b745172b..b3367c287a0 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/completion_items.rs @@ -86,7 +86,14 @@ impl<'a> NodeFinder<'a> { None, // trait_id false, // self_prefix ), - ModuleDefId::TypeId(struct_id) => vec![self.struct_completion_item(name, struct_id)], + ModuleDefId::TypeId(type_id) => { + let data_type = self.interner.get_type(type_id); + if data_type.borrow().is_struct() { + vec![self.struct_completion_item(name, type_id)] + } else { + vec![self.enum_completion_item(name, type_id)] + } + } ModuleDefId::TypeAliasId(id) => vec![self.type_alias_completion_item(name, id)], ModuleDefId::TraitId(trait_id) => vec![self.trait_completion_item(name, trait_id)], ModuleDefId::GlobalId(global_id) => vec![self.global_completion_item(name, global_id)], @@ -106,14 +113,18 @@ impl<'a> NodeFinder<'a> { name: impl Into, id: ModuleId, ) -> CompletionItem { - let completion_item = module_completion_item(name); - self.completion_item_with_doc_comments(ReferenceId::Module(id), completion_item) + let item = module_completion_item(name); + self.completion_item_with_doc_comments(ReferenceId::Module(id), item) } - fn struct_completion_item(&self, name: String, struct_id: TypeId) -> CompletionItem { - let completion_item = - simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); - self.completion_item_with_doc_comments(ReferenceId::Type(struct_id), completion_item) + fn struct_completion_item(&self, name: String, type_id: TypeId) -> CompletionItem { + let items = simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Type(type_id), items) + } + + fn enum_completion_item(&self, name: String, type_id: TypeId) -> CompletionItem { + let item = simple_completion_item(name.clone(), CompletionItemKind::ENUM, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Type(type_id), item) } pub(super) fn struct_field_completion_item( @@ -124,33 +135,42 @@ impl<'a> NodeFinder<'a> { field_index: usize, self_type: bool, ) -> CompletionItem { - let completion_item = struct_field_completion_item(field, typ, self_type); - self.completion_item_with_doc_comments( - ReferenceId::StructMember(struct_id, field_index), - completion_item, - ) + let item = struct_field_completion_item(field, typ, self_type); + let reference_id = ReferenceId::StructMember(struct_id, field_index); + self.completion_item_with_doc_comments(reference_id, item) } fn type_alias_completion_item(&self, name: String, id: TypeAliasId) -> CompletionItem { - let completion_item = - simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); - self.completion_item_with_doc_comments(ReferenceId::Alias(id), completion_item) + let item = simple_completion_item(name.clone(), CompletionItemKind::STRUCT, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Alias(id), item) } fn trait_completion_item(&self, name: String, trait_id: TraitId) -> CompletionItem { - let completion_item = - simple_completion_item(name.clone(), CompletionItemKind::INTERFACE, Some(name)); - self.completion_item_with_doc_comments(ReferenceId::Trait(trait_id), completion_item) + let item = simple_completion_item(name.clone(), CompletionItemKind::INTERFACE, Some(name)); + self.completion_item_with_doc_comments(ReferenceId::Trait(trait_id), item) } fn global_completion_item(&self, name: String, global_id: GlobalId) -> CompletionItem { let global = self.interner.get_global(global_id); let typ = self.interner.definition_type(global.definition_id); let description = typ.to_string(); + let item = simple_completion_item(name, CompletionItemKind::CONSTANT, Some(description)); + self.completion_item_with_doc_comments(ReferenceId::Global(global_id), item) + } - let completion_item = - simple_completion_item(name, CompletionItemKind::CONSTANT, Some(description)); - self.completion_item_with_doc_comments(ReferenceId::Global(global_id), completion_item) + pub(super) fn enum_variant_completion_item( + &self, + name: String, + type_id: TypeId, + variant_index: usize, + ) -> CompletionItem { + let kind = CompletionItemKind::ENUM_MEMBER; + let item = simple_completion_item(name.clone(), kind, Some(name.clone())); + let item = completion_item_with_detail(item, name); + self.completion_item_with_doc_comments( + ReferenceId::EnumVariant(type_id, variant_index), + item, + ) } #[allow(clippy::too_many_arguments)] @@ -354,6 +374,8 @@ impl<'a> NodeFinder<'a> { if let (Some(type_id), Some(variant_index)) = (func_meta.type_id, func_meta.enum_variant_index) { + completion_item.kind = Some(CompletionItemKind::ENUM_MEMBER); + self.completion_item_with_doc_comments( ReferenceId::EnumVariant(type_id, variant_index), completion_item, diff --git a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs index a3cd6b0d024..f670f26ffeb 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/completion/tests.rs @@ -3094,6 +3094,7 @@ fn main() { assert_eq!(items.len(), 1); let item = &items[0]; + assert_eq!(item.kind, Some(CompletionItemKind::ENUM_MEMBER)); assert_eq!(item.label, "Variant(…)".to_string()); let details = item.label_details.as_ref().unwrap(); @@ -3108,4 +3109,52 @@ fn main() { }; assert!(markdown.value.contains("Some docs")); } + + #[test] + async fn test_suggests_enum_variant_without_parameters() { + let src = r#" + enum Enum { + /// Some docs + Variant + } + + fn foo() { + Enum::Var>|< + } + "#; + let items = get_completions(src).await; + assert_eq!(items.len(), 1); + + let item = &items[0]; + assert_eq!(item.kind, Some(CompletionItemKind::ENUM_MEMBER)); + assert_eq!(item.label, "Variant".to_string()); + + let details = item.label_details.as_ref().unwrap(); + assert_eq!(details.description, Some("Variant".to_string())); + + assert_eq!(item.detail, Some("Variant".to_string())); + assert_eq!(item.insert_text, None); + + let Documentation::MarkupContent(markdown) = item.documentation.as_ref().unwrap() else { + panic!("Expected markdown docs"); + }; + assert!(markdown.value.contains("Some docs")); + } + + #[test] + async fn test_suggests_enum_type() { + let src = r#" + enum ThisIsAnEnum { + } + + fn foo() { + ThisIsA>|< + } + "#; + let items = get_completions(src).await; + assert_eq!(items.len(), 1); + + let item = &items[0]; + assert_eq!(item.kind, Some(CompletionItemKind::ENUM)); + } } diff --git a/noir/noir-repo/tooling/lsp/src/requests/inlay_hint.rs b/noir/noir-repo/tooling/lsp/src/requests/inlay_hint.rs index cbf4ed26ef9..8e091d1eb04 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/inlay_hint.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/inlay_hint.rs @@ -590,6 +590,7 @@ fn get_expression_name(expression: &Expression) -> Option { | ExpressionKind::InternedStatement(..) | ExpressionKind::Literal(..) | ExpressionKind::Unsafe(..) + | ExpressionKind::Match(_) | ExpressionKind::Error => None, } } diff --git a/noir/noir-repo/tooling/lsp/src/requests/test_run.rs b/noir/noir-repo/tooling/lsp/src/requests/test_run.rs index bd53526298e..e2d8edd46c8 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/test_run.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/test_run.rs @@ -74,7 +74,7 @@ fn on_test_run_request_inner( let test_functions = context.get_all_test_functions_in_crate_matching( &crate_id, - FunctionNameMatch::Exact(function_name), + &FunctionNameMatch::Exact(vec![function_name.clone()]), ); let (_, test_function) = test_functions.into_iter().next().ok_or_else(|| { diff --git a/noir/noir-repo/tooling/nargo_cli/build.rs b/noir/noir-repo/tooling/nargo_cli/build.rs index 21399662449..5e101bc0483 100644 --- a/noir/noir-repo/tooling/nargo_cli/build.rs +++ b/noir/noir-repo/tooling/nargo_cli/build.rs @@ -66,13 +66,14 @@ const INLINER_MIN_OVERRIDES: [(&str, i64); 1] = [ /// Some tests are expected to have warnings /// These should be fixed and removed from this list. -const TESTS_WITH_EXPECTED_WARNINGS: [&str; 3] = [ +const TESTS_WITH_EXPECTED_WARNINGS: [&str; 4] = [ // TODO(https://github.com/noir-lang/noir/issues/6238): remove from list once issue is closed "brillig_cast", // TODO(https://github.com/noir-lang/noir/issues/6238): remove from list once issue is closed "macros_in_comptime", // We issue a "experimental feature" warning for all enums until they're stabilized "enums", + "comptime_enums", ]; fn read_test_cases( @@ -430,6 +431,7 @@ fn generate_compile_success_no_bug_tests(test_file: &mut File, test_data_dir: &P &test_dir, "compile", r#" + nargo.arg("--enable-brillig-constraints-check"); nargo.assert().success().stderr(predicate::str::contains("bug:").not()); "#, &MatrixConfig::default(), @@ -459,6 +461,7 @@ fn generate_compile_success_with_bug_tests(test_file: &mut File, test_data_dir: &test_dir, "compile", r#" + nargo.arg("--enable-brillig-constraints-check"); nargo.assert().success().stderr(predicate::str::contains("bug:")); "#, &MatrixConfig::default(), diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs index fbfe5d18a36..dbb39b2b79e 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs @@ -35,7 +35,7 @@ pub(crate) struct CheckCommand { compile_options: CompileOptions, /// Just show the hash of each paackages, without actually performing the check. - #[clap(long)] + #[clap(long, hide = true)] show_program_hash: bool, } diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs index 6c8e548309c..42e0d0d2fe3 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs @@ -33,7 +33,7 @@ pub(crate) mod formatters; #[clap(visible_alias = "t")] pub(crate) struct TestCommand { /// If given, only tests with names containing this string will be run - test_name: Option, + test_names: Vec, /// Display output of `println` statements #[arg(long)] @@ -44,7 +44,7 @@ pub(crate) struct TestCommand { exact: bool, /// Print all matching test names. - #[clap(long)] + #[clap(long, hide = true)] list_tests: bool, #[clap(flatten)] @@ -129,15 +129,12 @@ pub(crate) fn run(args: TestCommand, config: NargoConfig) -> Result<(), CliError insert_all_files_for_workspace_into_file_manager(&workspace, &mut file_manager); let parsed_files = parse_all(&file_manager); - let pattern = match &args.test_name { - Some(name) => { - if args.exact { - FunctionNameMatch::Exact(name) - } else { - FunctionNameMatch::Contains(name) - } - } - None => FunctionNameMatch::Anything, + let pattern = if args.test_names.is_empty() { + FunctionNameMatch::Anything + } else if args.exact { + FunctionNameMatch::Exact(args.test_names.clone()) + } else { + FunctionNameMatch::Contains(args.test_names.clone()) }; let formatter: Box = if let Some(format) = args.format { @@ -165,7 +162,7 @@ struct TestRunner<'a> { parsed_files: &'a ParsedFiles, workspace: Workspace, args: &'a TestCommand, - pattern: FunctionNameMatch<'a>, + pattern: FunctionNameMatch, num_threads: usize, formatter: Box, } @@ -199,15 +196,31 @@ impl<'a> TestRunner<'a> { if tests_count == 0 { match &self.pattern { - FunctionNameMatch::Exact(pattern) => { - return Err(CliError::Generic(format!( - "Found 0 tests matching input '{pattern}'.", - ))) + FunctionNameMatch::Exact(patterns) => { + if patterns.len() == 1 { + return Err(CliError::Generic(format!( + "Found 0 tests matching '{}'.", + patterns.first().unwrap() + ))); + } else { + return Err(CliError::Generic(format!( + "Found 0 tests matching any of {}.", + patterns.join(", "), + ))); + } } - FunctionNameMatch::Contains(pattern) => { - return Err(CliError::Generic( - format!("Found 0 tests containing '{pattern}'.",), - )) + FunctionNameMatch::Contains(patterns) => { + if patterns.len() == 1 { + return Err(CliError::Generic(format!( + "Found 0 tests containing '{}'.", + patterns.first().unwrap() + ))); + } else { + return Err(CliError::Generic(format!( + "Found 0 tests containing any of {}.", + patterns.join(", ") + ))); + } } // If we are running all tests in a crate, having none is not an error FunctionNameMatch::Anything => {} @@ -472,7 +485,7 @@ impl<'a> TestRunner<'a> { check_crate_and_report_errors(&mut context, crate_id, &self.args.compile_options)?; Ok(context - .get_all_test_functions_in_crate_matching(&crate_id, self.pattern) + .get_all_test_functions_in_crate_matching(&crate_id, &self.pattern) .into_iter() .map(|(test_name, _)| test_name) .collect()) @@ -496,8 +509,8 @@ impl<'a> TestRunner<'a> { check_crate(&mut context, crate_id, &self.args.compile_options) .expect("Any errors should have occurred when collecting test functions"); - let test_functions = context - .get_all_test_functions_in_crate_matching(&crate_id, FunctionNameMatch::Exact(fn_name)); + let pattern = FunctionNameMatch::Exact(vec![fn_name.to_string()]); + let test_functions = context.get_all_test_functions_in_crate_matching(&crate_id, &pattern); let (_, test_function) = test_functions.first().expect("Test function should exist"); let blackbox_solver = S::default(); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs index bc4621c92ea..91d6f0066b1 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd/formatters.rs @@ -112,7 +112,7 @@ impl Formatter for PrettyFormatter { } }; - write!(writer, "[{}] Testing {}... ", &test_result.package_name, &test_result.name)?; + write!(writer, "[{}] Testing {} ... ", &test_result.package_name, &test_result.name)?; writer.flush()?; match &test_result.status { diff --git a/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs index ac5bf505005..2e3e3e2ae5a 100644 --- a/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs +++ b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs @@ -33,7 +33,7 @@ pub struct Options { impl Options { pub fn function_name_match(&self) -> FunctionNameMatch { match self.args.as_slice() { - [_test_name, lib] => FunctionNameMatch::Contains(lib.as_str()), + [_test_name, lib] => FunctionNameMatch::Contains(vec![lib.clone()]), _ => FunctionNameMatch::Anything, } } @@ -78,7 +78,7 @@ fn run_stdlib_tests(force_brillig: bool, inliner_aggressiveness: i64) { let test_functions = context.get_all_test_functions_in_crate_matching( context.stdlib_crate_id(), - opts.function_name_match(), + &opts.function_name_match(), ); let context = std::sync::Mutex::new(context); diff --git a/noir/noir-repo/tooling/nargo_fmt/src/formatter/enums.rs b/noir/noir-repo/tooling/nargo_fmt/src/formatter/enums.rs index b596ec95c94..2d1182a941c 100644 --- a/noir/noir-repo/tooling/nargo_fmt/src/formatter/enums.rs +++ b/noir/noir-repo/tooling/nargo_fmt/src/formatter/enums.rs @@ -48,9 +48,9 @@ impl<'a> Formatter<'a> { self.write_indentation(); self.write_identifier(variant.name); - if !variant.parameters.is_empty() { + if let Some(parameters) = variant.parameters { self.write_token(Token::LeftParen); - for (i, parameter) in variant.parameters.into_iter().enumerate() { + for (i, parameter) in parameters.into_iter().enumerate() { if i != 0 { self.write_comma(); self.write_space(); @@ -118,6 +118,7 @@ mod tests { Variant ( Field , i32 ) , // comment Another ( ), + Constant , } }"; let expected = "mod moo { enum Foo { @@ -125,7 +126,8 @@ mod tests { /// comment Variant(Field, i32), // comment - Another, + Another(), + Constant, } } "; diff --git a/noir/noir-repo/tooling/nargo_fmt/src/formatter/expression.rs b/noir/noir-repo/tooling/nargo_fmt/src/formatter/expression.rs index ef04276a605..98eabe10e7e 100644 --- a/noir/noir-repo/tooling/nargo_fmt/src/formatter/expression.rs +++ b/noir/noir-repo/tooling/nargo_fmt/src/formatter/expression.rs @@ -2,8 +2,8 @@ use noirc_frontend::{ ast::{ ArrayLiteral, BinaryOpKind, BlockExpression, CallExpression, CastExpression, ConstructorExpression, Expression, ExpressionKind, IfExpression, IndexExpression, - InfixExpression, Lambda, Literal, MemberAccessExpression, MethodCallExpression, - PrefixExpression, TypePath, UnaryOp, UnresolvedTypeData, + InfixExpression, Lambda, Literal, MatchExpression, MemberAccessExpression, + MethodCallExpression, PrefixExpression, TypePath, UnaryOp, UnresolvedTypeData, }, token::{Keyword, Token}, }; @@ -57,6 +57,9 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> { false, // force multiple lines )); } + ExpressionKind::Match(match_expression) => { + group.group(self.format_match_expression(*match_expression)); + } ExpressionKind::Variable(path) => { group.text(self.chunk(|formatter| { formatter.format_path(path); @@ -895,6 +898,68 @@ impl<'a, 'b> ChunkFormatter<'a, 'b> { group } + pub(super) fn format_match_expression( + &mut self, + match_expression: MatchExpression, + ) -> ChunkGroup { + let group_tag = self.new_group_tag(); + let mut group = self.format_match_expression_with_group_tag(match_expression, group_tag); + force_if_chunks_to_multiple_lines(&mut group, group_tag); + group + } + + pub(super) fn format_match_expression_with_group_tag( + &mut self, + match_expression: MatchExpression, + group_tag: GroupTag, + ) -> ChunkGroup { + let mut group = ChunkGroup::new(); + group.tag = Some(group_tag); + group.force_multiple_lines = true; + + group.text(self.chunk(|formatter| { + formatter.write_keyword(Keyword::Match); + formatter.write_space(); + })); + + self.format_expression(match_expression.expression, &mut group); + group.trailing_comment(self.skip_comments_and_whitespace_chunk()); + group.space(self); + + group.text(self.chunk(|formatter| { + formatter.write_left_brace(); + })); + + group.increase_indentation(); + for (pattern, branch) in match_expression.rules { + group.line(); + self.format_expression(pattern, &mut group); + group.text(self.chunk(|formatter| { + formatter.write_space(); + formatter.write_token(Token::FatArrow); + formatter.write_space(); + })); + self.format_expression(branch, &mut group); + + // Add a trailing comma regardless of whether the user specified one or not + group.text(self.chunk(|formatter| { + if formatter.token == Token::Comma { + formatter.write_current_token_and_bump(); + } else { + formatter.write(","); + } + })); + } + group.decrease_indentation(); + group.line(); + + group.text(self.chunk(|formatter| { + formatter.write_right_brace(); + })); + + group + } + fn format_index_expression(&mut self, index: IndexExpression) -> ChunkGroup { let mut group = ChunkGroup::new(); self.format_expression(index.collection, &mut group); @@ -2326,4 +2391,19 @@ global y = 1; "; assert_format_with_max_width(src, expected, " Foo { a: 1 },".len() - 1); } + + #[test] + fn format_match() { + let src = "fn main() { match x { A=>B,C => {D}E=>(), } }"; + // We should remove the block on D for single expressions in the future, + // unless D is an if or match. + let expected = "fn main() { + match x { + A => B, + C => { D }, + E => (), + } +}\n"; + assert_format(src, expected); + } } diff --git a/gaztec/.env b/playground/.env similarity index 100% rename from gaztec/.env rename to playground/.env diff --git a/gaztec/.gitignore b/playground/.gitignore similarity index 100% rename from gaztec/.gitignore rename to playground/.gitignore diff --git a/gaztec/.yarnrc.yml b/playground/.yarnrc.yml similarity index 100% rename from gaztec/.yarnrc.yml rename to playground/.yarnrc.yml diff --git a/gaztec/README.md b/playground/README.md similarity index 98% rename from gaztec/README.md rename to playground/README.md index 90ca9dfb346..83c892adcba 100644 --- a/gaztec/README.md +++ b/playground/README.md @@ -1,4 +1,4 @@ -# GAztec +# Aztec Playground Initial version of an "everything app" that can be used to test and benchmark Aztec. diff --git a/gaztec/eslint.config.js b/playground/eslint.config.js similarity index 100% rename from gaztec/eslint.config.js rename to playground/eslint.config.js diff --git a/gaztec/index.html b/playground/index.html similarity index 88% rename from gaztec/index.html rename to playground/index.html index 89ed3ef775f..7d5b3aca71c 100644 --- a/gaztec/index.html +++ b/playground/index.html @@ -3,7 +3,7 @@ - GAztec + Aztec Playground
diff --git a/playground/netlify.toml b/playground/netlify.toml new file mode 100644 index 00000000000..fa81267935d --- /dev/null +++ b/playground/netlify.toml @@ -0,0 +1,5 @@ +[[headers]] + for = "/*" + [headers.values] + Cross-Origin-Embedder-Policy = "require-corp" + Cross-Origin-Opener-Policy = "same-origin" diff --git a/gaztec/package.json b/playground/package.json similarity index 98% rename from gaztec/package.json rename to playground/package.json index 0d0d6d8d0de..08cbfe557ce 100644 --- a/gaztec/package.json +++ b/playground/package.json @@ -1,5 +1,5 @@ { - "name": "gaztec", + "name": "playground", "packageManager": "yarn@4.5.2", "private": true, "version": "0.0.0", diff --git a/gaztec/src/App.tsx b/playground/src/App.tsx similarity index 100% rename from gaztec/src/App.tsx rename to playground/src/App.tsx diff --git a/gaztec/src/assets/Aztec_logo.png b/playground/src/assets/Aztec_logo.png similarity index 100% rename from gaztec/src/assets/Aztec_logo.png rename to playground/src/assets/Aztec_logo.png diff --git a/gaztec/src/aztecEnv.ts b/playground/src/aztecEnv.ts similarity index 100% rename from gaztec/src/aztecEnv.ts rename to playground/src/aztecEnv.ts diff --git a/gaztec/src/common.styles.tsx b/playground/src/common.styles.tsx similarity index 100% rename from gaztec/src/common.styles.tsx rename to playground/src/common.styles.tsx diff --git a/gaztec/src/components/common/copyToClipboardButton.tsx b/playground/src/components/common/copyToClipboardButton.tsx similarity index 100% rename from gaztec/src/components/common/copyToClipboardButton.tsx rename to playground/src/components/common/copyToClipboardButton.tsx diff --git a/gaztec/src/components/common/fnParameter.tsx b/playground/src/components/common/fnParameter.tsx similarity index 100% rename from gaztec/src/components/common/fnParameter.tsx rename to playground/src/components/common/fnParameter.tsx diff --git a/gaztec/src/components/contract/components/createAuthwitDialog.tsx b/playground/src/components/contract/components/createAuthwitDialog.tsx similarity index 100% rename from gaztec/src/components/contract/components/createAuthwitDialog.tsx rename to playground/src/components/contract/components/createAuthwitDialog.tsx diff --git a/gaztec/src/components/contract/components/deployContractDialog.tsx b/playground/src/components/contract/components/deployContractDialog.tsx similarity index 100% rename from gaztec/src/components/contract/components/deployContractDialog.tsx rename to playground/src/components/contract/components/deployContractDialog.tsx diff --git a/gaztec/src/components/contract/components/registerContractDialog.tsx b/playground/src/components/contract/components/registerContractDialog.tsx similarity index 100% rename from gaztec/src/components/contract/components/registerContractDialog.tsx rename to playground/src/components/contract/components/registerContractDialog.tsx diff --git a/gaztec/src/components/contract/contract.tsx b/playground/src/components/contract/contract.tsx similarity index 100% rename from gaztec/src/components/contract/contract.tsx rename to playground/src/components/contract/contract.tsx diff --git a/gaztec/src/components/contract/dropzone.css b/playground/src/components/contract/dropzone.css similarity index 100% rename from gaztec/src/components/contract/dropzone.css rename to playground/src/components/contract/dropzone.css diff --git a/gaztec/src/components/home/home.tsx b/playground/src/components/home/home.tsx similarity index 100% rename from gaztec/src/components/home/home.tsx rename to playground/src/components/home/home.tsx diff --git a/gaztec/src/components/logPanel/logPanel.tsx b/playground/src/components/logPanel/logPanel.tsx similarity index 100% rename from gaztec/src/components/logPanel/logPanel.tsx rename to playground/src/components/logPanel/logPanel.tsx diff --git a/gaztec/src/components/sidebar/components/addNetworkDialog.tsx b/playground/src/components/sidebar/components/addNetworkDialog.tsx similarity index 100% rename from gaztec/src/components/sidebar/components/addNetworkDialog.tsx rename to playground/src/components/sidebar/components/addNetworkDialog.tsx diff --git a/gaztec/src/components/sidebar/components/addSenderDialog.tsx b/playground/src/components/sidebar/components/addSenderDialog.tsx similarity index 100% rename from gaztec/src/components/sidebar/components/addSenderDialog.tsx rename to playground/src/components/sidebar/components/addSenderDialog.tsx diff --git a/gaztec/src/components/sidebar/components/createAccountDialog.tsx b/playground/src/components/sidebar/components/createAccountDialog.tsx similarity index 100% rename from gaztec/src/components/sidebar/components/createAccountDialog.tsx rename to playground/src/components/sidebar/components/createAccountDialog.tsx diff --git a/gaztec/src/components/sidebar/components/txsPanel.tsx b/playground/src/components/sidebar/components/txsPanel.tsx similarity index 100% rename from gaztec/src/components/sidebar/components/txsPanel.tsx rename to playground/src/components/sidebar/components/txsPanel.tsx diff --git a/gaztec/src/components/sidebar/sidebar.tsx b/playground/src/components/sidebar/sidebar.tsx similarity index 99% rename from gaztec/src/components/sidebar/sidebar.tsx rename to playground/src/components/sidebar/sidebar.tsx index b5b040b3603..142a50a76c8 100644 --- a/gaztec/src/components/sidebar/sidebar.tsx +++ b/playground/src/components/sidebar/sidebar.tsx @@ -244,9 +244,9 @@ export function SidebarComponent() {
- GAztec + Playground
Connect diff --git a/gaztec/src/main.tsx b/playground/src/main.tsx similarity index 100% rename from gaztec/src/main.tsx rename to playground/src/main.tsx diff --git a/gaztec/src/utils/constants.ts b/playground/src/utils/constants.ts similarity index 100% rename from gaztec/src/utils/constants.ts rename to playground/src/utils/constants.ts diff --git a/gaztec/src/utils/conversion.ts b/playground/src/utils/conversion.ts similarity index 100% rename from gaztec/src/utils/conversion.ts rename to playground/src/utils/conversion.ts diff --git a/gaztec/src/utils/storage.ts b/playground/src/utils/storage.ts similarity index 100% rename from gaztec/src/utils/storage.ts rename to playground/src/utils/storage.ts diff --git a/gaztec/src/utils/txs.ts b/playground/src/utils/txs.ts similarity index 100% rename from gaztec/src/utils/txs.ts rename to playground/src/utils/txs.ts diff --git a/gaztec/src/vite-env.d.ts b/playground/src/vite-env.d.ts similarity index 100% rename from gaztec/src/vite-env.d.ts rename to playground/src/vite-env.d.ts diff --git a/gaztec/tsconfig.json b/playground/tsconfig.json similarity index 100% rename from gaztec/tsconfig.json rename to playground/tsconfig.json diff --git a/gaztec/vite.config.ts b/playground/vite.config.ts similarity index 100% rename from gaztec/vite.config.ts rename to playground/vite.config.ts diff --git a/gaztec/yarn.lock b/playground/yarn.lock similarity index 99% rename from gaztec/yarn.lock rename to playground/yarn.lock index f8b6dd718fc..545d938e9e2 100644 --- a/gaztec/yarn.lock +++ b/playground/yarn.lock @@ -5,57 +5,57 @@ __metadata: version: 8 cacheKey: 10c0 -"@aztec/accounts@link:../yarn-project/accounts::locator=gaztec%40workspace%3A.": +"@aztec/accounts@link:../yarn-project/accounts::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/accounts@link:../yarn-project/accounts::locator=gaztec%40workspace%3A." + resolution: "@aztec/accounts@link:../yarn-project/accounts::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/aztec.js@link:../yarn-project/aztec.js::locator=gaztec%40workspace%3A.": +"@aztec/aztec.js@link:../yarn-project/aztec.js::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/aztec.js@link:../yarn-project/aztec.js::locator=gaztec%40workspace%3A." + resolution: "@aztec/aztec.js@link:../yarn-project/aztec.js::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/bb-prover@link:../yarn-project/bb-prover::locator=gaztec%40workspace%3A.": +"@aztec/bb-prover@link:../yarn-project/bb-prover::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/bb-prover@link:../yarn-project/bb-prover::locator=gaztec%40workspace%3A." + resolution: "@aztec/bb-prover@link:../yarn-project/bb-prover::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/circuits.js@link:../yarn-project/circuits.js::locator=gaztec%40workspace%3A.": +"@aztec/circuits.js@link:../yarn-project/circuits.js::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/circuits.js@link:../yarn-project/circuits.js::locator=gaztec%40workspace%3A." + resolution: "@aztec/circuits.js@link:../yarn-project/circuits.js::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/foundation@link:../yarn-project/foundation::locator=gaztec%40workspace%3A.": +"@aztec/foundation@link:../yarn-project/foundation::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/foundation@link:../yarn-project/foundation::locator=gaztec%40workspace%3A." + resolution: "@aztec/foundation@link:../yarn-project/foundation::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/key-store@link:../yarn-project/key-store::locator=gaztec%40workspace%3A.": +"@aztec/key-store@link:../yarn-project/key-store::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/key-store@link:../yarn-project/key-store::locator=gaztec%40workspace%3A." + resolution: "@aztec/key-store@link:../yarn-project/key-store::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/kv-store@link:../yarn-project/kv-store::locator=gaztec%40workspace%3A.": +"@aztec/kv-store@link:../yarn-project/kv-store::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/kv-store@link:../yarn-project/kv-store::locator=gaztec%40workspace%3A." + resolution: "@aztec/kv-store@link:../yarn-project/kv-store::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/pxe@link:../yarn-project/pxe::locator=gaztec%40workspace%3A.": +"@aztec/pxe@link:../yarn-project/pxe::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/pxe@link:../yarn-project/pxe::locator=gaztec%40workspace%3A." + resolution: "@aztec/pxe@link:../yarn-project/pxe::locator=playground%40workspace%3A." languageName: node linkType: soft -"@aztec/simulator@link:../yarn-project/simulator::locator=gaztec%40workspace%3A.": +"@aztec/simulator@link:../yarn-project/simulator::locator=playground%40workspace%3A.": version: 0.0.0-use.local - resolution: "@aztec/simulator@link:../yarn-project/simulator::locator=gaztec%40workspace%3A." + resolution: "@aztec/simulator@link:../yarn-project/simulator::locator=playground%40workspace%3A." languageName: node linkType: soft @@ -2607,46 +2607,6 @@ __metadata: languageName: node linkType: hard -"gaztec@workspace:.": - version: 0.0.0-use.local - resolution: "gaztec@workspace:." - dependencies: - "@aztec/accounts": "link:../yarn-project/accounts" - "@aztec/aztec.js": "link:../yarn-project/aztec.js" - "@aztec/bb-prover": "link:../yarn-project/bb-prover" - "@aztec/circuits.js": "link:../yarn-project/circuits.js" - "@aztec/foundation": "link:../yarn-project/foundation" - "@aztec/key-store": "link:../yarn-project/key-store" - "@aztec/kv-store": "link:../yarn-project/kv-store" - "@aztec/pxe": "link:../yarn-project/pxe" - "@aztec/simulator": "link:../yarn-project/simulator" - "@emotion/react": "npm:^11.14.0" - "@emotion/styled": "npm:^11.14.0" - "@eslint/js": "npm:^9.18.0" - "@fontsource/roboto": "npm:^5.1.1" - "@mui/icons-material": "npm:^6.3.1" - "@mui/material": "npm:^6.3.1" - "@mui/styles": "npm:^6.3.1" - "@types/node": "npm:^22.10.5" - "@types/react": "npm:^19.0.6" - "@types/react-dom": "npm:^19.0.3" - "@vitejs/plugin-react-swc": "npm:^3.7.2" - eslint: "npm:^9.13.0" - eslint-plugin-react-hooks: "npm:^5.1.0" - eslint-plugin-react-refresh: "npm:^0.4.18" - globals: "npm:^15.14.0" - nosleep.js: "npm:^0.12.0" - react: "npm:^18.3.1" - react-dom: "npm:^18.3.1" - react-dropzone: "npm:^14.3.5" - typescript: "npm:~5.7.3" - typescript-eslint: "npm:^8.11.0" - vite: "npm:^6.0.11" - vite-plugin-node-polyfills: "npm:^0.23.0" - vite-plugin-static-copy: "npm:^2.2.0" - languageName: unknown - linkType: soft - "get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6": version: 1.2.7 resolution: "get-intrinsic@npm:1.2.7" @@ -3856,6 +3816,46 @@ __metadata: languageName: node linkType: hard +"playground@workspace:.": + version: 0.0.0-use.local + resolution: "playground@workspace:." + dependencies: + "@aztec/accounts": "link:../yarn-project/accounts" + "@aztec/aztec.js": "link:../yarn-project/aztec.js" + "@aztec/bb-prover": "link:../yarn-project/bb-prover" + "@aztec/circuits.js": "link:../yarn-project/circuits.js" + "@aztec/foundation": "link:../yarn-project/foundation" + "@aztec/key-store": "link:../yarn-project/key-store" + "@aztec/kv-store": "link:../yarn-project/kv-store" + "@aztec/pxe": "link:../yarn-project/pxe" + "@aztec/simulator": "link:../yarn-project/simulator" + "@emotion/react": "npm:^11.14.0" + "@emotion/styled": "npm:^11.14.0" + "@eslint/js": "npm:^9.18.0" + "@fontsource/roboto": "npm:^5.1.1" + "@mui/icons-material": "npm:^6.3.1" + "@mui/material": "npm:^6.3.1" + "@mui/styles": "npm:^6.3.1" + "@types/node": "npm:^22.10.5" + "@types/react": "npm:^19.0.6" + "@types/react-dom": "npm:^19.0.3" + "@vitejs/plugin-react-swc": "npm:^3.7.2" + eslint: "npm:^9.13.0" + eslint-plugin-react-hooks: "npm:^5.1.0" + eslint-plugin-react-refresh: "npm:^0.4.18" + globals: "npm:^15.14.0" + nosleep.js: "npm:^0.12.0" + react: "npm:^18.3.1" + react-dom: "npm:^18.3.1" + react-dropzone: "npm:^14.3.5" + typescript: "npm:~5.7.3" + typescript-eslint: "npm:^8.11.0" + vite: "npm:^6.0.11" + vite-plugin-node-polyfills: "npm:^0.23.0" + vite-plugin-static-copy: "npm:^2.2.0" + languageName: unknown + linkType: soft + "possible-typed-array-names@npm:^1.0.0": version: 1.0.0 resolution: "possible-typed-array-names@npm:1.0.0" diff --git a/spartan/metrics/values/prod.yaml b/spartan/metrics/values/prod.yaml index c2c2b33f5e1..d84f0621192 100644 --- a/spartan/metrics/values/prod.yaml +++ b/spartan/metrics/values/prod.yaml @@ -1,6 +1,17 @@ opentelemetry-collector: + replicaCount: 3 + resources: + requests: + memory: 12Gi + cpu: "1.5" nodeSelector: node-type: infra + pool: spot + tolerations: + - key: "cloud.google.com/gke-spot" + operator: "Equal" + value: "true" + effect: "NoSchedule" ports: jaeger-compact: enabled: false @@ -29,14 +40,21 @@ prometheus: server: resources: requests: - memory: 7Gi - cpu: 1.5 + memory: 26Gi + cpu: "3.5" nodeSelector: node-type: infra + pool: spot + tolerations: + - key: "cloud.google.com/gke-spot" + operator: "Equal" + value: "true" + effect: "NoSchedule" + persistentVolume: enabled: true size: 100Gi - replicaCount: 10 + replicaCount: 3 statefulSet: enabled: true alertmanager: @@ -57,6 +75,10 @@ tempo: # https://artifacthub.io/packages/helm/grafana/grafana grafana: + resources: + requests: + memory: 5Gi + cpu: "1.5" nodeSelector: node-type: infra service: diff --git a/spartan/releases/testnet/aztec-spartan.sh b/spartan/releases/testnet/aztec-spartan.sh index 68954742765..83bb41238bc 100755 --- a/spartan/releases/testnet/aztec-spartan.sh +++ b/spartan/releases/testnet/aztec-spartan.sh @@ -227,13 +227,18 @@ configure_environment() { COINBASE="$CLI_COINBASE" else while true; do - read -p "Validator Address (default: 0xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa): " COINBASE - COINBASE=${COINBASE:-0xbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa} - if [[ "$COINBASE" =~ ^0x[a-fA-F0-9]{40}$ ]]; then - break + read -p "Validator Address (Coinbase): " COINBASE + + if [ -z "$COINBASE" ]; then + echo -e "${RED}Error: Validator Address (Coinbase) is required${NC}" else - echo -e "${RED}Error: Invalid COINBASE address. Please enter a valid Ethereum address.${NC}" + if [[ "$COINBASE" =~ ^0x[a-fA-F0-9]{40}$ ]]; then + break + else + echo -e "${RED}Error: Invalid COINBASE address. Please enter a valid Ethereum address.${NC}" + fi fi + done fi @@ -302,6 +307,7 @@ P2P_UDP_LISTEN_ADDR=0.0.0.0:${P2P_PORT} P2P_TCP_LISTEN_ADDR=0.0.0.0:${P2P_PORT} DATA_DIRECTORY=/var/lib/aztec PEER_ID_PRIVATE_KEY=${PEER_ID_PRIVATE_KEY} +COINBASE=${COINBASE} EOF # Generate docker-compose.yml diff --git a/spartan/terraform/gke-cluster/cluster/main.tf b/spartan/terraform/gke-cluster/cluster/main.tf index 4d5e93f0ed7..afa68c485b0 100644 --- a/spartan/terraform/gke-cluster/cluster/main.tf +++ b/spartan/terraform/gke-cluster/cluster/main.tf @@ -273,3 +273,93 @@ resource "google_container_node_pool" "spot_nodes_2core" { auto_upgrade = false } } + +# Create 2 core high memory spot instance node pool with autoscaling, used for metrics +resource "google_container_node_pool" "spot_nodes_2core-highmem" { + name = "${var.cluster_name}-2core-highmem-spot" + location = var.zone + cluster = var.cluster_name + version = var.node_version + # Enable autoscaling + autoscaling { + min_node_count = 0 + max_node_count = 8 + } + + # Node configuration + node_config { + machine_type = "n2-highmem-2" + spot = true + + service_account = var.service_account + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform" + ] + + labels = { + env = "production" + pool = "spot" + local-ssd = "false" + node-type = "infra" + } + tags = ["aztec-gke-node", "spot"] + + # Spot instance termination handler + taint { + key = "cloud.google.com/gke-spot" + value = "true" + effect = "NO_SCHEDULE" + } + } + + # Management configuration + management { + auto_repair = true + auto_upgrade = false + } +} + +# Create 4 core high memory spot instance node pool with autoscaling, used for metrics +resource "google_container_node_pool" "spot_nodes_4core-highmem" { + name = "${var.cluster_name}-4core-highmem-spot" + location = var.zone + cluster = var.cluster_name + version = var.node_version + # Enable autoscaling + autoscaling { + min_node_count = 0 + max_node_count = 8 + } + + # Node configuration + node_config { + machine_type = "n2-highmem-4" + spot = true + + service_account = var.service_account + oauth_scopes = [ + "https://www.googleapis.com/auth/cloud-platform" + ] + + labels = { + env = "production" + pool = "spot" + local-ssd = "false" + node-type = "infra" + } + tags = ["aztec-gke-node", "spot"] + + # Spot instance termination handler + taint { + key = "cloud.google.com/gke-spot" + value = "true" + effect = "NO_SCHEDULE" + } + } + + # Management configuration + management { + auto_repair = true + auto_upgrade = false + } +} diff --git a/yarn-project/accounts/src/defaults/index.ts b/yarn-project/accounts/src/defaults/index.ts index d5b399a1dd2..237e118c3ff 100644 --- a/yarn-project/accounts/src/defaults/index.ts +++ b/yarn-project/accounts/src/defaults/index.ts @@ -1,7 +1,7 @@ /** * The `@aztec/accounts/defaults` export provides the base class {@link DefaultAccountContract} for implementing account contracts that use the default entrypoint payload module. * - * Read more in {@link https://docs.aztec.network/developers/wallets/writing_an_account_contract | Writing an account contract}. + * Read more in {@link https://docs.aztec.network/developers/tutorials/codealong/contract_tutorials/write_accounts_contract | Writing an account contract}. * * @packageDocumentation */ diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index f21e3859243..8383dc7c2f7 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -59,6 +59,7 @@ import { computePublicDataTreeLeafSlot, siloNullifier } from '@aztec/circuits.js import { EpochCache } from '@aztec/epoch-cache'; import { type L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { compactArray } from '@aztec/foundation/collection'; import { type Logger, createLogger } from '@aztec/foundation/log'; import { DateProvider, Timer } from '@aztec/foundation/timer'; import { type AztecKVStore } from '@aztec/kv-store'; @@ -500,6 +501,15 @@ export class AztecNodeService implements AztecNode, Traceable { return Promise.resolve(this.p2pClient!.getTxByHashFromPool(txHash)); } + /** + * Method to retrieve txs from the mempool or unfinalised chain. + * @param txHash - The transaction hash to return. + * @returns - The txs if it exists. + */ + public async getTxsByHash(txHashes: TxHash[]) { + return compactArray(await Promise.all(txHashes.map(txHash => this.getTxByHash(txHash)))); + } + /** * Find the indexes of the given leaves in the given tree. * @param blockNumber - The block number at which to get the data or 'latest' for latest data diff --git a/yarn-project/aztec.js/README.md b/yarn-project/aztec.js/README.md index 8fdc97fa521..ff0540e71d8 100644 --- a/yarn-project/aztec.js/README.md +++ b/yarn-project/aztec.js/README.md @@ -1,6 +1,6 @@ # Aztec.js -Aztec.js is a library that provides APIs for managing accounts and interacting with contracts on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](https://docs.aztec.network/reference/aztecjs/pxe) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. +Aztec.js is a library that provides APIs for managing accounts and interacting with contracts on the Aztec network. It communicates with the [Private eXecution Environment (PXE)](https://docs.aztec.network/developers/reference/aztecjs/pxe) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. ## Installing diff --git a/yarn-project/aztec.js/src/contract/index.ts b/yarn-project/aztec.js/src/contract/index.ts index b69395de86e..265886aea9c 100644 --- a/yarn-project/aztec.js/src/contract/index.ts +++ b/yarn-project/aztec.js/src/contract/index.ts @@ -1,7 +1,7 @@ /** * The `contract` module provides utilities for deploying and interacting with contracts, based on a * `Wallet` instance and a compiled artifact. Refer to the {@link account} module for how to obtain a valid - * `Wallet` instance, and to the {@link https://docs.aztec.network/developers/contracts/compiling | Compiling contracts} + * `Wallet` instance, and to the {@link https://docs.aztec.network/developers/guides/smart_contracts/how_to_compile_contract | Compiling contracts} * section of the documentation for how to generate an artifact out of your Noir source code. * * The {@link Contract} class is the main class in this module, and provides static methods for deploying @@ -30,7 +30,7 @@ * has synchronized its changes. * * @remarks If you are using typescript, consider using the - * {@link https://docs.aztec.network/developers/contracts/compiling#typescript-interfaces | autogenerated type-safe interfaces} + * {@link https://docs.aztec.network/developers/guides/smart_contracts/how_to_compile_contract#typescript-interfaces | autogenerated type-safe interfaces} * for interacting with your contracts. * * @packageDocumentation diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 540129e0bd6..161f4e7d944 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.74.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.73.0...aztec-package-v0.74.0) (2025-02-04) + + +### Miscellaneous + +* Ensure new kv-store is used on the server ([#11662](https://github.com/AztecProtocol/aztec-packages/issues/11662)) ([aee1420](https://github.com/AztecProtocol/aztec-packages/commit/aee14208a42f9b5b7f9aef4b6e0d92e303a265c1)) + ## [0.73.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.72.1...aztec-package-v0.73.0) (2025-02-01) @@ -27,7 +34,7 @@ ### Features -* Gaztec ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) +* Aztec Playground ([#11229](https://github.com/AztecProtocol/aztec-packages/issues/11229)) ([79f810d](https://github.com/AztecProtocol/aztec-packages/commit/79f810dc682d41154eb723e5bdf4c54c0681becb)) * Lazy wasm pt. 2 ([#11410](https://github.com/AztecProtocol/aztec-packages/issues/11410)) ([01510f4](https://github.com/AztecProtocol/aztec-packages/commit/01510f45aa5d385a08584df674d9caf9522e6be2)) * Lazy wasm pt3 ([#11435](https://github.com/AztecProtocol/aztec-packages/issues/11435)) ([7068d05](https://github.com/AztecProtocol/aztec-packages/commit/7068d055d91a6e81e6fbb670e17c77ee209a1a80)) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 8807c4fa2c4..b2945af85e2 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.73.0", + "version": "0.74.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts index d32d4be9735..9d2fbbe7af4 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.test.ts @@ -281,6 +281,11 @@ describe('AztecNodeApiSchema', () => { expect(response).toBeInstanceOf(Tx); }); + it('getTxsByHash', async () => { + const response = await context.client.getTxsByHash([TxHash.random()]); + expect(response[0]).toBeInstanceOf(Tx); + }); + it('getPublicStorageAt', async () => { const response = await context.client.getPublicStorageAt(await AztecAddress.random(), Fr.random(), 1); expect(response).toBeInstanceOf(Fr); @@ -560,6 +565,10 @@ class MockAztecNode implements AztecNode { expect(txHash).toBeInstanceOf(TxHash); return Promise.resolve(Tx.random()); } + async getTxsByHash(txHashes: TxHash[]): Promise { + expect(txHashes[0]).toBeInstanceOf(TxHash); + return [await Tx.random()]; + } getPublicStorageAt(contract: AztecAddress, slot: Fr, _blockNumber: number | 'latest'): Promise { expect(contract).toBeInstanceOf(AztecAddress); expect(slot).toBeInstanceOf(Fr); diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 5f376871ff6..1b5afd8e476 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -53,7 +53,7 @@ import { type SequencerConfig, SequencerConfigSchema } from './configs.js'; import { type L2BlockNumber, L2BlockNumberSchema } from './l2_block_number.js'; import { NullifierMembershipWitness } from './nullifier_membership_witness.js'; import { type ProverConfig, ProverConfigSchema } from './prover-client.js'; -import { type ProverCoordination, ProverCoordinationApiSchema } from './prover-coordination.js'; +import { type ProverCoordination } from './prover-coordination.js'; /** * The aztec node. @@ -371,6 +371,13 @@ export interface AztecNode */ getTxByHash(txHash: TxHash): Promise; + /** + * Method to retrieve multiple pending txs. + * @param txHash - The transaction hashes to return. + * @returns The pending txs if exist. + */ + getTxsByHash(txHashes: TxHash[]): Promise; + /** * Gets the storage value at the given contract storage slot. * @@ -453,9 +460,8 @@ export interface AztecNode } export const AztecNodeApiSchema: ApiSchemaFor = { - ...ProverCoordinationApiSchema, - getL2Tips: z.function().args().returns(L2TipsSchema), + findLeavesIndexes: z .function() .args(L2BlockNumberSchema, z.nativeEnum(MerkleTreeId), z.array(schemas.Fr)) @@ -567,6 +573,8 @@ export const AztecNodeApiSchema: ApiSchemaFor = { getTxByHash: z.function().args(TxHash.schema).returns(Tx.schema.optional()), + getTxsByHash: z.function().args(z.array(TxHash.schema)).returns(z.array(Tx.schema)), + getPublicStorageAt: z.function().args(schemas.AztecAddress, schemas.Fr, L2BlockNumberSchema).returns(schemas.Fr), getBlockHeader: z.function().args(optional(L2BlockNumberSchema)).returns(BlockHeader.schema), diff --git a/yarn-project/circuit-types/src/interfaces/prover-coordination.ts b/yarn-project/circuit-types/src/interfaces/prover-coordination.ts index f0df43c3451..396f21cf36b 100644 --- a/yarn-project/circuit-types/src/interfaces/prover-coordination.ts +++ b/yarn-project/circuit-types/src/interfaces/prover-coordination.ts @@ -15,6 +15,13 @@ export interface ProverCoordination { */ getTxByHash(txHash: TxHash): Promise; + /** + * Returns a set of transactions given their hashes if available. + * @param txHashes - The hashes of the transactions, used as an ID. + * @returns The transactions, if found, 'undefined' otherwise. + */ + getTxsByHash(txHashes: TxHash[]): Promise; + /** * Receives a quote for an epoch proof and stores it in its EpochProofQuotePool * @param quote - The quote to store @@ -24,5 +31,6 @@ export interface ProverCoordination { export const ProverCoordinationApiSchema: ApiSchemaFor = { getTxByHash: z.function().args(TxHash.schema).returns(Tx.schema.optional()), + getTxsByHash: z.function().args(z.array(TxHash.schema)).returns(z.array(Tx.schema)), addEpochProofQuote: z.function().args(EpochProofQuote.schema).returns(z.void()), }; diff --git a/yarn-project/cli/src/cmds/misc/update.ts b/yarn-project/cli/src/cmds/misc/update.ts index fa8265e425c..34c3d3eed50 100644 --- a/yarn-project/cli/src/cmds/misc/update.ts +++ b/yarn-project/cli/src/cmds/misc/update.ts @@ -10,7 +10,7 @@ import { updateAztecNr } from './update/noir.js'; import { getNewestVersion, updateAztecDeps, updateLockfile } from './update/npm.js'; const AZTECJS_PACKAGE = '@aztec/aztec.js'; -const UPDATE_DOCS_URL = 'https://docs.aztec.network/developers/updating'; +const UPDATE_DOCS_URL = 'https://docs.aztec.network/developers/guides/local_env/versions-updating'; export async function updateProject( projectPath: string, diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index c097c040546..4331ad70de2 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -716,6 +716,7 @@ export async function createAndSyncProverNode( const aztecNodeWithoutStop = { addEpochProofQuote: aztecNode.addEpochProofQuote.bind(aztecNode), getTxByHash: aztecNode.getTxByHash.bind(aztecNode), + getTxsByHash: aztecNode.getTxsByHash.bind(aztecNode), stop: () => Promise.resolve(), }; diff --git a/yarn-project/entrypoints/src/index.ts b/yarn-project/entrypoints/src/index.ts index 75ba38e75d6..fb1c0fedaba 100644 --- a/yarn-project/entrypoints/src/index.ts +++ b/yarn-project/entrypoints/src/index.ts @@ -1,7 +1,7 @@ /** * The `@aztec/accounts/defaults` export provides the base class {@link DefaultAccountContract} for implementing account contracts that use the default entrypoint payload module. * - * Read more in {@link https://docs.aztec.network/tutorials/write_accounts_contract | Writing an account contract}. + * Read more in {@link https://docs.aztec.network/developers/tutorials/codealong/contract_tutorials/write_accounts_contract | Writing an account contract}. * * @packageDocumentation */ diff --git a/yarn-project/epoch-cache/src/epoch_cache.ts b/yarn-project/epoch-cache/src/epoch_cache.ts index 1cbe315c2bb..eaa2fca5d45 100644 --- a/yarn-project/epoch-cache/src/epoch_cache.ts +++ b/yarn-project/epoch-cache/src/epoch_cache.ts @@ -142,7 +142,7 @@ export class EpochCache extends EventEmitter<{ committeeChanged: [EthAddress[], } /** - * Get the ABI encoding of the proposer index - see Leonidas.sol _computeProposerIndex + * Get the ABI encoding of the proposer index - see ValidatorSelectionLib.sol computeProposerIndex */ getProposerIndexEncoding(epoch: bigint, slot: bigint, seed: bigint): `0x${string}` { return encodeAbiParameters( diff --git a/yarn-project/ethereum/src/contracts/rollup.ts b/yarn-project/ethereum/src/contracts/rollup.ts index 45013f3b30a..6fc021d316d 100644 --- a/yarn-project/ethereum/src/contracts/rollup.ts +++ b/yarn-project/ethereum/src/contracts/rollup.ts @@ -113,7 +113,7 @@ export class RollupContract { @memoize getTargetCommitteeSize() { - return this.rollup.read.TARGET_COMMITTEE_SIZE(); + return this.rollup.read.getTargetCommitteeSize(); } @memoize diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index fbecce8f06a..594a9bf981d 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -261,7 +261,7 @@ export class Fr extends BaseField { return fromHexString(buf, Fr); } - throw new Error('Tried to create a Fr from an invalid string'); + throw new Error(`Tried to create a Fr from an invalid string: ${buf}`); } /** @@ -412,7 +412,7 @@ export class Fq extends BaseField { return fromHexString(buf, Fq); } - throw new Error('Tried to create a Fq from an invalid string'); + throw new Error(`Tried to create a Fq from an invalid string: ${buf}`); } /** diff --git a/yarn-project/p2p/src/client/p2p_client.test.ts b/yarn-project/p2p/src/client/p2p_client.test.ts index a2690fe2ae6..b68d7e6ce52 100644 --- a/yarn-project/p2p/src/client/p2p_client.test.ts +++ b/yarn-project/p2p/src/client/p2p_client.test.ts @@ -201,8 +201,7 @@ describe('In-Memory P2P Client', () => { }); describe('Chain prunes', () => { - // TODO(#10737) flake cc Maddiaa0 - it.skip('moves the tips on a chain reorg', async () => { + it('moves the tips on a chain reorg', async () => { blockSource.setProvenBlockNumber(0); await client.start(); diff --git a/yarn-project/p2p/src/client/p2p_client.ts b/yarn-project/p2p/src/client/p2p_client.ts index 0cb4a5b303d..cc4a76494c4 100644 --- a/yarn-project/p2p/src/client/p2p_client.ts +++ b/yarn-project/p2p/src/client/p2p_client.ts @@ -10,6 +10,7 @@ import { type P2PApi, type P2PClientType, type PeerInfo, + type ProverCoordination, type Tx, type TxHash, } from '@aztec/circuit-types'; @@ -62,130 +63,131 @@ export interface P2PSyncState { /** * Interface of a P2P client. **/ -export type P2P = P2PApi & { - /** - * Broadcasts a block proposal to other peers. - * - * @param proposal - the block proposal - */ - broadcastProposal(proposal: BlockProposal): void; - - /** - * Queries the EpochProofQuote pool for quotes for the given epoch - * - * @param epoch - the epoch to query - * @returns EpochProofQuotes - */ - getEpochProofQuotes(epoch: bigint): Promise; - - /** - * Adds an EpochProofQuote to the pool and broadcasts an EpochProofQuote to other peers. - * - * @param quote - the quote to broadcast - */ - addEpochProofQuote(quote: EpochProofQuote): Promise; - - /** - * Registers a callback from the validator client that determines how to behave when - * foreign block proposals are received - * - * @param handler - A function taking a received block proposal and producing an attestation - */ - // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963 - // ^ This pattern is not my favorite (md) - registerBlockProposalHandler(handler: (block: BlockProposal) => Promise): void; - - /** - * Request a list of transactions from another peer by their tx hashes. - * @param txHashes - Hashes of the txs to query. - * @returns A list of transactions or undefined if the transactions are not found. - */ - requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]>; - - /** - * Request a transaction from another peer by its tx hash. - * @param txHash - Hash of the tx to query. - */ - requestTxByHash(txHash: TxHash): Promise; - - /** - * Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers. - * @param tx - The transaction. - **/ - sendTx(tx: Tx): Promise; - - /** - * Deletes 'txs' from the pool, given hashes. - * NOT used if we use sendTx as reconcileTxPool will handle this. - * @param txHashes - Hashes to check. - **/ - deleteTxs(txHashes: TxHash[]): Promise; - - /** - * Returns a transaction in the transaction pool by its hash. - * @param txHash - Hash of tx to return. - * @returns A single tx or undefined. - */ - getTxByHashFromPool(txHash: TxHash): Promise; - - /** - * Returns a transaction in the transaction pool by its hash, requesting it from the network if it is not found. - * @param txHash - Hash of tx to return. - * @returns A single tx or undefined. - */ - getTxByHash(txHash: TxHash): Promise; - - /** - * Returns an archived transaction from the transaction pool by its hash. - * @param txHash - Hash of tx to return. - * @returns A single tx or undefined. - */ - getArchivedTxByHash(txHash: TxHash): Promise; - - /** - * Returns whether the given tx hash is flagged as pending or mined. - * @param txHash - Hash of the tx to query. - * @returns Pending or mined depending on its status, or undefined if not found. - */ - getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | undefined>; - - /** Returns an iterator over pending txs on the mempool. */ - iteratePendingTxs(): AsyncIterableIterator; - - /** Returns the number of pending txs in the mempool. */ - getPendingTxCount(): Promise; - - /** - * Starts the p2p client. - * @returns A promise signalling the completion of the block sync. - */ - start(): Promise; - - /** - * Stops the p2p client. - * @returns A promise signalling the completion of the stop process. - */ - stop(): Promise; - - /** - * Indicates if the p2p client is ready for transaction submission. - * @returns A boolean flag indicating readiness. - */ - isReady(): boolean; - - /** - * Returns the current status of the p2p client. - */ - getStatus(): Promise; - - /** - * Returns the ENR of this node, if any. - */ - getEnr(): ENR | undefined; - - /** Identifies a p2p client. */ - isP2PClient(): true; -}; +export type P2P = ProverCoordination & + P2PApi & { + /** + * Broadcasts a block proposal to other peers. + * + * @param proposal - the block proposal + */ + broadcastProposal(proposal: BlockProposal): void; + + /** + * Queries the EpochProofQuote pool for quotes for the given epoch + * + * @param epoch - the epoch to query + * @returns EpochProofQuotes + */ + getEpochProofQuotes(epoch: bigint): Promise; + + /** + * Adds an EpochProofQuote to the pool and broadcasts an EpochProofQuote to other peers. + * + * @param quote - the quote to broadcast + */ + addEpochProofQuote(quote: EpochProofQuote): Promise; + + /** + * Registers a callback from the validator client that determines how to behave when + * foreign block proposals are received + * + * @param handler - A function taking a received block proposal and producing an attestation + */ + // REVIEW: https://github.com/AztecProtocol/aztec-packages/issues/7963 + // ^ This pattern is not my favorite (md) + registerBlockProposalHandler(handler: (block: BlockProposal) => Promise): void; + + /** + * Request a list of transactions from another peer by their tx hashes. + * @param txHashes - Hashes of the txs to query. + * @returns A list of transactions or undefined if the transactions are not found. + */ + requestTxs(txHashes: TxHash[]): Promise<(Tx | undefined)[]>; + + /** + * Request a transaction from another peer by its tx hash. + * @param txHash - Hash of the tx to query. + */ + requestTxByHash(txHash: TxHash): Promise; + + /** + * Verifies the 'tx' and, if valid, adds it to local tx pool and forwards it to other peers. + * @param tx - The transaction. + **/ + sendTx(tx: Tx): Promise; + + /** + * Deletes 'txs' from the pool, given hashes. + * NOT used if we use sendTx as reconcileTxPool will handle this. + * @param txHashes - Hashes to check. + **/ + deleteTxs(txHashes: TxHash[]): Promise; + + /** + * Returns a transaction in the transaction pool by its hash. + * @param txHash - Hash of tx to return. + * @returns A single tx or undefined. + */ + getTxByHashFromPool(txHash: TxHash): Promise; + + /** + * Returns a transaction in the transaction pool by its hash, requesting it from the network if it is not found. + * @param txHash - Hash of tx to return. + * @returns A single tx or undefined. + */ + getTxByHash(txHash: TxHash): Promise; + + /** + * Returns an archived transaction from the transaction pool by its hash. + * @param txHash - Hash of tx to return. + * @returns A single tx or undefined. + */ + getArchivedTxByHash(txHash: TxHash): Promise; + + /** + * Returns whether the given tx hash is flagged as pending or mined. + * @param txHash - Hash of the tx to query. + * @returns Pending or mined depending on its status, or undefined if not found. + */ + getTxStatus(txHash: TxHash): Promise<'pending' | 'mined' | undefined>; + + /** Returns an iterator over pending txs on the mempool. */ + iteratePendingTxs(): AsyncIterableIterator; + + /** Returns the number of pending txs in the mempool. */ + getPendingTxCount(): Promise; + + /** + * Starts the p2p client. + * @returns A promise signalling the completion of the block sync. + */ + start(): Promise; + + /** + * Stops the p2p client. + * @returns A promise signalling the completion of the stop process. + */ + stop(): Promise; + + /** + * Indicates if the p2p client is ready for transaction submission. + * @returns A boolean flag indicating readiness. + */ + isReady(): boolean; + + /** + * Returns the current status of the p2p client. + */ + getStatus(): Promise; + + /** + * Returns the ENR of this node, if any. + */ + getEnr(): ENR | undefined; + + /** Identifies a p2p client. */ + isP2PClient(): true; + }; /** * The P2P client implementation. @@ -467,6 +469,17 @@ export class P2PClient return tx; } + /** + * Uses the batched Request Response protocol to request a set of transactions from the network. + */ + public async requestTxsByHash(txHashes: TxHash[]): Promise { + const txs = (await this.p2pService.sendBatchRequest(ReqRespSubProtocol.TX, txHashes)) ?? []; + await this.txPool.addTxs(txs); + const txHashesStr = txHashes.map(tx => tx.toString()).join(', '); + this.log.debug(`Received batched txs ${txHashesStr} (${txs.length} / ${txHashes.length}}) from peers`); + return txs as Tx[]; + } + public getPendingTxs(): Promise { return Promise.resolve(this.getTxs('pending')); } @@ -529,6 +542,27 @@ export class P2PClient return this.requestTxByHash(txHash); } + /** + * Returns transactions in the transaction pool by hash. + * If a transaction is not in the pool, it will be requested from the network. + * @param txHashes - Hashes of the transactions to look for. + * @returns The txs found, not necessarily on the same order as the hashes. + */ + async getTxsByHash(txHashes: TxHash[]): Promise { + const txs = await Promise.all(txHashes.map(txHash => this.txPool.getTxByHash(txHash))); + const missingTxHashes = txs + .map((tx, index) => [tx, index] as const) + .filter(([tx, _index]) => !tx) + .map(([_tx, index]) => txHashes[index]); + + if (missingTxHashes.length === 0) { + return txs as Tx[]; + } + + const missingTxs = await this.requestTxsByHash(missingTxHashes); + return txs.filter((tx): tx is Tx => !!tx).concat(missingTxs); + } + /** * Returns an archived transaction in the transaction pool by its hash. * @param txHash - Hash of the archived transaction to look for. @@ -662,7 +696,7 @@ export class P2PClient blocks.map(async block => this.synchedBlockHashes.set(block.number, (await block.hash()).toString())), ); await this.synchedLatestBlockNumber.set(lastBlockNum); - this.log.debug(`Synched to latest block ${lastBlockNum}`); + this.log.verbose(`Synched to latest block ${lastBlockNum}`); await this.startServiceIfSynched(); } diff --git a/yarn-project/prover-node/src/prover-node.test.ts b/yarn-project/prover-node/src/prover-node.test.ts index c959cd0daf7..9c6729e4988 100644 --- a/yarn-project/prover-node/src/prover-node.test.ts +++ b/yarn-project/prover-node/src/prover-node.test.ts @@ -151,8 +151,8 @@ describe('prover-node', () => { l2BlockSource.getL1Constants.mockResolvedValue(EmptyL1RollupConstants); // Coordination plays along and returns a tx whenever requested - mockCoordination.getTxByHash.mockImplementation(hash => - Promise.resolve(mock({ getTxHash: () => Promise.resolve(hash) })), + mockCoordination.getTxsByHash.mockImplementation(hashes => + Promise.resolve(hashes.map(hash => mock({ getTxHash: () => Promise.resolve(hash) }))), ); // A sample claim @@ -193,7 +193,7 @@ describe('prover-node', () => { }); it('does not send a quote if there is a tx missing from coordinator', async () => { - mockCoordination.getTxByHash.mockResolvedValue(undefined); + mockCoordination.getTxsByHash.mockResolvedValue([]); await proverNode.handleEpochCompleted(10n); expect(coordination.addEpochProofQuote).not.toHaveBeenCalled(); }); @@ -293,32 +293,11 @@ describe('prover-node', () => { expect(jobs.length).toEqual(1); }); - it('retries acquiring txs if they are not immediately available', async () => { - l2BlockSource.getL2EpochNumber.mockResolvedValue(11n); - publisher.getProofClaim.mockResolvedValue(claim); - const mockGetTxByHash = mockCoordination.getTxByHash.getMockImplementation(); - mockCoordination.getTxByHash.mockResolvedValue(undefined); - - await proverNode.start(); - await sleep(100); - - // initially no job will be started because the txs aren't available - expect(jobs).toHaveLength(0); - expect(mockCoordination.getTxByHash).toHaveBeenCalled(); - - mockCoordination.getTxByHash.mockImplementation(mockGetTxByHash); - await sleep(100); - - // now it should have all the txs necessary to start proving - expect(jobs[0].epochNumber).toEqual(10n); - expect(jobs.length).toEqual(1); - }); - it('does not start proving if txs are not all available', async () => { l2BlockSource.getL2EpochNumber.mockResolvedValue(11n); publisher.getProofClaim.mockResolvedValue(claim); - mockCoordination.getTxByHash.mockResolvedValue(undefined); + mockCoordination.getTxsByHash.mockResolvedValue([]); await proverNode.start(); await sleep(2000); @@ -405,6 +384,12 @@ describe('prover-node', () => { jest.spyOn(p2pClient, 'getTxByHash').mockImplementation(mockGetTxByHash); jest.spyOn(otherP2PClient, 'getTxByHash').mockImplementation(mockGetTxByHash); + // And getTxsByHash just for good measure + const mockGetTxsByHash = (hashes: TxHash[]) => + Promise.resolve(hashes.map(hash => mock({ getTxHash: () => Promise.resolve(hash) }))); + jest.spyOn(p2pClient, 'getTxsByHash').mockImplementation(mockGetTxsByHash); + jest.spyOn(otherP2PClient, 'getTxsByHash').mockImplementation(mockGetTxsByHash); + await Promise.all([p2pClient.start(), otherP2PClient.start()]); // Sleep to enable peer discovery diff --git a/yarn-project/prover-node/src/prover-node.ts b/yarn-project/prover-node/src/prover-node.ts index 05a2f0a16da..55b19b334e1 100644 --- a/yarn-project/prover-node/src/prover-node.ts +++ b/yarn-project/prover-node/src/prover-node.ts @@ -17,12 +17,9 @@ import { tryStop, } from '@aztec/circuit-types'; import { type ContractDataSource } from '@aztec/circuits.js'; -import { asyncPool } from '@aztec/foundation/async-pool'; import { compact } from '@aztec/foundation/collection'; import { memoize } from '@aztec/foundation/decorators'; -import { TimeoutError } from '@aztec/foundation/error'; import { createLogger } from '@aztec/foundation/log'; -import { retryUntil } from '@aztec/foundation/retry'; import { DateProvider } from '@aztec/foundation/timer'; import { type Maybe } from '@aztec/foundation/types'; import { type P2P } from '@aztec/p2p'; @@ -333,68 +330,20 @@ export class ProverNode implements ClaimsMonitorHandler, EpochMonitorHandler, Pr } private async gatherTxs(epochNumber: bigint, blocks: L2Block[]) { - let txsToFind: TxHash[] = []; - const txHashToBlock = new Map(); - const results = new Map(); - - for (const block of blocks) { - for (const tx of block.body.txEffects) { - txsToFind.push(tx.txHash); - txHashToBlock.set(tx.txHash.toString(), block.number); - } - } + const txsToFind: TxHash[] = blocks.flatMap(block => block.body.txEffects.map(tx => tx.txHash)); + const txs = await this.coordination.getTxsByHash(txsToFind); - const totalTxsRequired = txsToFind.length; - this.log.info( - `Gathering a total of ${totalTxsRequired} txs for epoch=${epochNumber} made up of ${blocks.length} blocks`, - { epochNumber }, - ); - - let iteration = 0; - try { - await retryUntil( - async () => { - const batch = [...txsToFind]; - txsToFind = []; - const batchResults = await asyncPool(this.options.txGatheringMaxParallelRequests, batch, async txHash => { - const tx = await this.coordination.getTxByHash(txHash); - return [txHash, tx] as const; - }); - let found = 0; - for (const [txHash, maybeTx] of batchResults) { - if (maybeTx) { - found++; - results.set(txHash.toString(), maybeTx); - } else { - txsToFind.push(txHash); - } - } - - this.log.verbose( - `Gathered ${found}/${batch.length} txs in iteration ${iteration} for epoch ${epochNumber}. In total ${results.size}/${totalTxsRequired} have been retrieved.`, - { epochNumber }, - ); - iteration++; - - // stop when we found all transactions - return txsToFind.length === 0; - }, - 'Gather txs', - this.options.txGatheringTimeoutMs / 1_000, - this.options.txGatheringIntervalMs / 1_000, - ); - } catch (err) { - if (err && err instanceof TimeoutError) { - const notFoundList = txsToFind - .map(txHash => `${txHash.toString()} (block ${txHashToBlock.get(txHash.toString())})`) - .join(', '); - throw new Error(`Txs not found for epoch ${epochNumber}: ${notFoundList}`); - } else { - throw err; - } + if (txs.length === txsToFind.length) { + this.log.verbose(`Gathered all ${txs.length} txs for epoch ${epochNumber}`, { epochNumber }); + return txs; } - return Array.from(results.values()); + const txHashesFound = await Promise.all(txs.map(tx => tx.getTxHash())); + const missingTxHashes = txsToFind + .filter(txHashToFind => !txHashesFound.some(txHashFound => txHashToFind.equals(txHashFound))) + .join(', '); + + throw new Error(`Txs not found for epoch ${epochNumber}: ${missingTxHashes}`); } /** Extracted for testing purposes. */ diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 7d94afb9170..aae22071d09 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -680,7 +680,7 @@ export class PXEService implements PXE { const contract = await this.db.getContract(to); if (!contract) { throw new Error( - `Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/reference/common_errors/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`, + `Unknown contract ${to}: add it to PXE Service by calling server.addContracts(...).\nSee docs for context: https://docs.aztec.network/developers/reference/debugging/aztecnr-errors#unknown-contract-0x0-add-it-to-pxe-by-calling-serveraddcontracts`, ); } diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index b7b58425128..4bfd14aeed0 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -488,6 +488,45 @@ describe('sequencer', () => { expectPublisherProposeL2Block(postFlushTxHashes); }); + it('settles on the chain tip before it starts building a block', async () => { + // this test simulates a synch happening right after the sequencer starts building a bloxk + // simulate every component being synched + const firstBlock = await L2Block.random(1); + const currentTip = firstBlock; + const syncedToL2Block = { number: currentTip.number, hash: (await currentTip.hash()).toString() }; + worldState.status.mockImplementation(() => + Promise.resolve({ state: WorldStateRunningState.IDLE, syncedToL2Block }), + ); + p2p.getStatus.mockImplementation(() => Promise.resolve({ state: P2PClientState.IDLE, syncedToL2Block })); + l2BlockSource.getL2Tips.mockImplementation(() => + Promise.resolve({ + latest: syncedToL2Block, + proven: { number: 0, hash: undefined }, + finalized: { number: 0, hash: undefined }, + }), + ); + l1ToL2MessageSource.getBlockNumber.mockImplementation(() => Promise.resolve(currentTip.number)); + + // simulate a synch happening right after + l2BlockSource.getBlockNumber.mockResolvedValueOnce(currentTip.number); + l2BlockSource.getBlockNumber.mockResolvedValueOnce(currentTip.number + 1); + // now the new tip is actually block 2 + l2BlockSource.getBlock.mockImplementation(n => + n === -1 + ? L2Block.random(currentTip.number + 1) + : n === currentTip.number + ? Promise.resolve(currentTip) + : Promise.resolve(undefined), + ); + + publisher.canProposeAtNextEthBlock.mockResolvedValueOnce(undefined); + await sequencer.doRealWork(); + expect(publisher.enqueueProposeL2Block).not.toHaveBeenCalled(); + // even though the chain tip moved, the sequencer should still have tried to build a block against the old archive + // this should get caught by the rollup + expect(publisher.canProposeAtNextEthBlock).toHaveBeenCalledWith(currentTip.archive.root.toBuffer()); + }); + it('aborts building a block if the chain moves underneath it', async () => { const tx = await makeTx(); mockPendingTxs([tx]); @@ -560,6 +599,11 @@ describe('sequencer', () => { l2BlockSource.getBlock.mockResolvedValue(L2Block.random(blockNumber - 1)); l2BlockSource.getBlockNumber.mockResolvedValue(blockNumber - 1); + l2BlockSource.getL2Tips.mockResolvedValue({ + latest: { number: blockNumber - 1, hash }, + proven: { number: 0, hash: undefined }, + finalized: { number: 0, hash: undefined }, + }); l1ToL2MessageSource.getBlockNumber.mockResolvedValue(blockNumber - 1); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 0b7a475ed86..7c7253f3b8e 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -19,6 +19,7 @@ import { GENESIS_ARCHIVE_ROOT, Gas, type GlobalVariables, + INITIAL_L2_BLOCK_NUM, StateReference, } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -232,20 +233,18 @@ export class Sequencer { protected async doRealWork() { this.setState(SequencerState.SYNCHRONIZING, 0n); // Update state when the previous block has been synced - const prevBlockSynced = await this.isBlockSynced(); + const chainTip = await this.getChainTip(); // Do not go forward with new block if the previous one has not been mined and processed - if (!prevBlockSynced) { + if (!chainTip) { return; } this.setState(SequencerState.PROPOSER_CHECK, 0n); - const chainTip = await this.l2BlockSource.getBlock(-1); - - const newBlockNumber = (chainTip?.header.globalVariables.blockNumber.toNumber() ?? 0) + 1; + const newBlockNumber = chainTip.blockNumber + 1; // If we cannot find a tip archive, assume genesis. - const chainTipArchive = chainTip?.archive.root ?? new Fr(GENESIS_ARCHIVE_ROOT); + const chainTipArchive = chainTip.archive; const slot = await this.slotForProposal(chainTipArchive.toBuffer(), BigInt(newBlockNumber)); if (!slot) { @@ -253,7 +252,7 @@ export class Sequencer { return; } - this.log.info(`Can propose block ${newBlockNumber} at slot ${slot}`); + this.log.debug(`Can propose block ${newBlockNumber} at slot ${slot}`); const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables( new Fr(newBlockNumber), @@ -763,14 +762,16 @@ export class Sequencer { * We don't check against the previous block submitted since it may have been reorg'd out. * @returns Boolean indicating if our dependencies are synced to the latest block. */ - protected async isBlockSynced() { + protected async getChainTip(): Promise<{ blockNumber: number; archive: Fr } | undefined> { const syncedBlocks = await Promise.all([ this.worldState.status().then((s: WorldStateSynchronizerStatus) => s.syncedToL2Block), this.l2BlockSource.getL2Tips().then(t => t.latest), - this.p2pClient.getStatus().then(s => s.syncedToL2Block.number), + this.p2pClient.getStatus().then(p2p => p2p.syncedToL2Block), this.l1ToL2MessageSource.getBlockNumber(), ] as const); + const [worldState, l2BlockSource, p2p, l1ToL2MessageSource] = syncedBlocks; + const result = // check that world state has caught up with archiver // note that the archiver reports undefined hash for the genesis block @@ -780,18 +781,33 @@ export class Sequencer { // this should change to hashes once p2p client handles reorgs // and once we stop pretending that the l1tol2message source is not // just the archiver under a different name - p2p >= l2BlockSource.number && - l1ToL2MessageSource >= l2BlockSource.number; + (!l2BlockSource.hash || p2p.hash === l2BlockSource.hash) && + l1ToL2MessageSource === l2BlockSource.number; this.log.debug(`Sequencer sync check ${result ? 'succeeded' : 'failed'}`, { worldStateNumber: worldState.number, worldStateHash: worldState.hash, l2BlockSourceNumber: l2BlockSource.number, l2BlockSourceHash: l2BlockSource.hash, - p2pNumber: p2p, + p2pNumber: p2p.number, + p2pHash: p2p.hash, l1ToL2MessageSourceNumber: l1ToL2MessageSource, }); - return result; + + if (!result) { + return undefined; + } + if (worldState.number >= INITIAL_L2_BLOCK_NUM) { + const block = await this.l2BlockSource.getBlock(worldState.number); + if (!block) { + // this shouldn't really happen because a moment ago we checked that all components were in synch + return undefined; + } + + return { blockNumber: block.number, archive: block.archive.root }; + } else { + return { blockNumber: INITIAL_L2_BLOCK_NUM - 1, archive: new Fr(GENESIS_ARCHIVE_ROOT) }; + } } private getSlotStartTimestamp(slotNumber: number | bigint): number { diff --git a/yarn-project/txe/src/node/txe_node.ts b/yarn-project/txe/src/node/txe_node.ts index 5b788eb156f..39bf2d1e4cd 100644 --- a/yarn-project/txe/src/node/txe_node.ts +++ b/yarn-project/txe/src/node/txe_node.ts @@ -568,6 +568,10 @@ export class TXENode implements AztecNode { throw new Error('TXE Node method getTxByHash not implemented'); } + getTxsByHash(_txHashes: TxHash[]): Promise { + throw new Error('TXE Node method getTxByHash not implemented'); + } + /** * Gets the storage value at the given contract storage slot. * diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 2182451baf4..50410b0a233 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -220,7 +220,7 @@ function getStorageLayout(input: NoirCompiledContract) { const name = field.name; const slot = field.value.fields[0].value as IntegerValue; acc[name] = { - slot: slot.value, + slot: `0x${slot.value}`, }; return acc; }, {});