diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index eaec104ed72..7d8cb1ed5b7 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -6,7 +6,9 @@ name: Mirror to noir repo # Don't allow multiple of these running at once: concurrency: group: ${{ github.workflow }} + cancel-in-progress: false on: + workflow_dispatch: {} push: branches: - master @@ -19,45 +21,128 @@ jobs: runs-on: ubuntu-latest steps: + - name: Get noir master's last sync commit + id: last_merge_hash + uses: actions/github-script@v7 + with: + script: | + // NOTE: more robust heuristic needed if aztecbot opens different kinds of PRs + const response = await github.rest.search.commits({ + q: 'author:AztecBot committer:web-flow repo:noir-lang/noir sort:committer-date' + }); + console.log(response.data.items); + return response.data.items[0].sha; + - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 0 token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} + + - name: Setup env + run: | + set -xue # print commands + # Enable gh executable. We spread out the API requests between the github actions bot token, and aztecbot + export GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" + # Do we have a PR active? + PR_URL=$(gh pr list --repo noir-lang/noir --head aztec-packages --json url --jq ".[0].url") + echo "PR_URL=$PR_URL" >> $GITHUB_ENV + + # compute_commit_message: Create a filtered git log for release-please changelog / metadata + function compute_commit_message() { + # Get the last sync PR's last commit state + LAST_MERGED_PR_HASH=`gh pr list --repo=noir-lang/noir --state merged --head aztec-packages --json headRefOid --jq=.[0].headRefOid` + # Use a commit heuristic where we look at when .gitrepo first started to look at that commit state (through a push) + COMMIT_HEURISTIC=$(git log -p -S"$LAST_MERGED_PR_HASH" --reverse --source -- noir/.gitrepo | grep -m 1 '^commit' | awk '{print $2}' || true) + if [[ " $COMMIT_HEURISTIC" = "" ]] ; then + # It it fails, just use our gitrepo parent commit (last time we pushed or pulled) + COMMIT_HEURISTIC=$BASE_AZTEC_COMMIT + fi + # Create a filtered git log for release-please changelog / metadata + RAW_MESSAGE=$(git log --pretty=format:"%s" $COMMIT_HEURISTIC..HEAD -- noir/ ':!noir/.gitrepo' | grep -v 'git subrepo' || true) + # Fix Aztec PR links and output message + echo "$RAW_MESSAGE" | sed -E 's/\(#([0-9]+)\)/(https:\/\/github.com\/AztecProtocol\/aztec-packages\/pull\/\1)/g' + } + echo "$(compute_commit_message)" >> .COMMIT_MESSAGE + # We push using git subrepo (https://github.com/ingydotnet/git-subrepo) - # with some logic to recover from squashed parent commits - # We push to subrepo, commit to master. The commit is needed - # to continue to replay. If we still hit issues such as this - # action failing due to upstream changes, a manual resolution - # PR with ./scripts/git_subrepo.sh pull will be needed. + # and push all Aztec commits as a single commit with metadata. - name: Push to branch run: | + set -xue # print commands + # Enable gh executable. We spread out the API requests between the github actions bot token, and aztecbot + export GH_TOKEN="${{ secrets.GITHUB_TOKEN }}" SUBREPO_PATH=noir BRANCH=aztec-packages + if [[ "$PR_URL" == "" ]]; then + # if no staging branch, we can overwrite + STAGING_BRANCH=$BRANCH + else + # otherwise we first reset our staging branch + STAGING_BRANCH=$BRANCH-staging + fi # identify ourselves, needed to commit git config --global user.name AztecBot git config --global user.email tech@aztecprotocol.com - if ./scripts/git_subrepo.sh push $SUBREPO_PATH --branch=$BRANCH; then - git commit --amend -m "$(git log -1 --pretty=%B) [skip ci]" - git push - else - echo "Problems syncing noir. We may need to pull the subrepo." - exit 1 + BASE_NOIR_COMMIT=`git config --file=noir/.gitrepo subrepo.commit` + BASE_AZTEC_COMMIT=`git config --file=noir/.gitrepo subrepo.parent` + + # clone noir repo for manipulations, we use aztec bot token for writeability + git clone https://x-access-token:${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}@github.com/noir-lang/noir.git noir-repo + + # reset_pr: Reset aztec-packages staging. If no PR, this is the PR branch. + function reset_noir_staging_branch() { + cd noir-repo + git checkout $STAGING_BRANCH || git checkout -b $STAGING_BRANCH + git reset --hard "$BASE_NOIR_COMMIT" + # Reset our branch to our expected target + git push origin $STAGING_BRANCH --force + cd .. + } + # force_sync_staging: Push to our aztec-packages staging branch. + function force_sync_staging() { + MESSAGE=$(cat .COMMIT_MESSAGE) + git commit --allow-empty -m"chore: Sync to noir-lang/noir" -m"$MESSAGE" + COMMIT=$(git rev-parse HEAD) + # Now push to it with subrepo with computed commit messages + if ./scripts/git-subrepo/lib/git-subrepo push $SUBREPO_PATH --squash --branch=$STAGING_BRANCH; then + git reset $COMMIT + git commit --allow-empty --amend -am "$(git log -1 --pretty=%B) [skip ci]" + git push + else + echo "Problems syncing noir. We may need to pull the subrepo." + exit 1 + fi + } + # merge_staging_branch: Merge our staging branch into aztec-packages. + function merge_staging_branch() { + # Fix PR branch + cd noir-repo + git fetch # see recent change + git checkout $BRANCH || git checkout -b $BRANCH + git merge -Xtheirs $STAGING_BRANCH + git push origin $BRANCH + cd .. + } + reset_noir_staging_branch + force_sync_staging + if [[ "$PR_URL" != "" ]]; then + merge_staging_branch fi - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 - repository: noir-lang/noir - token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} - - name: Create PR for Aztec Branch - continue-on-error: true - uses: repo-sync/pull-request@v2 - with: - github_token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} - pr_title: 'feat: Sync commits from `aztec-packages`' - pr_body: 'Development from [aztec-packages](https://github.com/AztecProtocol/aztec-packages).' - destination_branch: 'master' - source_branch: 'aztec-packages' + - name: Update PR + run: | + set -xue # print commands + MESSAGE=$(cat .COMMIT_MESSAGE) + # Formatted for updating the PR, overrides for release-please commit message parsing + PR_BODY="""BEGIN_COMMIT_OVERRIDE + $MESSAGE + END_COMMIT_OVERRIDE""" + # for cross-opening PR in noir repo, we use aztecbot's token + export GH_TOKEN=${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} + if [[ "$PR_URL" == "" ]]; then + gh pr create --repo noir-lang/noir --title "feat: Sync from aztec-packages" --body "$PR_BODY" --base master --head aztec-packages + else + gh pr edit "$PR_URL" --body "$PR_BODY" + fi diff --git a/.github/workflows/protocol-circuits-gate-diff.yml b/.github/workflows/protocol-circuits-gate-diff.yml index e1e8b96b472..38f0fbb3437 100644 --- a/.github/workflows/protocol-circuits-gate-diff.yml +++ b/.github/workflows/protocol-circuits-gate-diff.yml @@ -13,8 +13,6 @@ jobs: steps: - name: Checkout Code uses: actions/checkout@v3 - with: - ref: ${{ inputs.tag || env.GITHUB_REF }} - name: Install bleeding edge cmake run: | diff --git a/.github/workflows/publish-bb.yml b/.github/workflows/publish-bb.yml index 6793f999745..d295b9fdcf8 100644 --- a/.github/workflows/publish-bb.yml +++ b/.github/workflows/publish-bb.yml @@ -149,12 +149,15 @@ jobs: ref: ${{ inputs.tag || env.GITHUB_REF }} - name: Create Mac Build Environment - run: brew install cmake ninja + run: brew install cmake ninja llvm@16 - name: Compile Barretenberg working-directory: barretenberg/cpp run: | - cmake --preset default -DCMAKE_BUILD_TYPE=RelWithAssert + export PATH="/usr/local/opt/llvm@16/bin:$PATH" + export LDFLAGS="-L/usr/local/opt/llvm@16/lib" + export CPPFLAGS="-I/usr/local/opt/llvm@16/include" + cmake -DCMAKE_BUILD_TYPE=RelWithAssert --preset default cmake --build --preset default --target bb - name: Package barretenberg artifact diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6bed8a5067f..36a1f8578e9 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,5 +1,5 @@ { - ".": "0.21.0", - "barretenberg": "0.21.0", - "barretenberg/ts": "0.21.0" + ".": "0.23.0", + "barretenberg": "0.23.0", + "barretenberg/ts": "0.23.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index f5528b86d2d..d94320511c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,193 @@ # Changelog +## [0.23.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.22.0...aztec-packages-v0.23.0) (2024-02-07) + + +### ⚠ BREAKING CHANGES + +* rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) +* init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) [skip ci] + +### Features + +* Add additional error types to verifier contract and revert early ([#4464](https://github.com/AztecProtocol/aztec-packages/issues/4464)) ([5e16063](https://github.com/AztecProtocol/aztec-packages/commit/5e160632bb7d48e676583e1b62b604c25fc4af4e)) +* Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Allow nested arrays and vectors in Brillig foreign calls ([#4478](https://github.com/AztecProtocol/aztec-packages/issues/4478)) ([bbfa337](https://github.com/AztecProtocol/aztec-packages/commit/bbfa3374d20b44c49870e21c61cbb2ab5f7ae117)) +* Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* **avm:** Back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* **avm:** Generic bytecode deserialization ([#4441](https://github.com/AztecProtocol/aztec-packages/issues/4441)) ([934fabc](https://github.com/AztecProtocol/aztec-packages/commit/934fabc8d3706e601eb3dca546c4545b58a10006)), closes [#4304](https://github.com/AztecProtocol/aztec-packages/issues/4304) +* **avm:** Support variable size SET opcode ([#4465](https://github.com/AztecProtocol/aztec-packages/issues/4465)) ([545b334](https://github.com/AztecProtocol/aztec-packages/commit/545b3341f73e5b20c3ac39b75f4783e7bdecac5d)) +* **aztec-nr:** Initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* **bb:** Op counting mode ([#4437](https://github.com/AztecProtocol/aztec-packages/issues/4437)) ([5d00cff](https://github.com/AztecProtocol/aztec-packages/commit/5d00cff86a1f76f5279dad6a0bd4e02c8211b225)) +* Canonical instance deployer contract ([#4436](https://github.com/AztecProtocol/aztec-packages/issues/4436)) ([b4acc8c](https://github.com/AztecProtocol/aztec-packages/commit/b4acc8c6227f1551998aab9a300891b560479b9c)) +* Init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Updating global vars with fees ([#4421](https://github.com/AztecProtocol/aztec-packages/issues/4421)) ([34109eb](https://github.com/AztecProtocol/aztec-packages/commit/34109eb9c068df87bbb04164a1531605f3a2c47d)), closes [#3824](https://github.com/AztecProtocol/aztec-packages/issues/3824) + + +### Bug Fixes + +* Delay rming bins till right before installing them. ([#4474](https://github.com/AztecProtocol/aztec-packages/issues/4474)) ([fabeac8](https://github.com/AztecProtocol/aztec-packages/commit/fabeac8b3f9971763a9a723ac6983e5ea8330f46)) +* **docs:** Add redirect for top google hit giving 404 ([#4487](https://github.com/AztecProtocol/aztec-packages/issues/4487)) ([e1d3f5a](https://github.com/AztecProtocol/aztec-packages/commit/e1d3f5ad6f45966845983a01eed8167afe7c137f)) +* **docs:** Update mdx files to md ([#4459](https://github.com/AztecProtocol/aztec-packages/issues/4459)) ([e67d94b](https://github.com/AztecProtocol/aztec-packages/commit/e67d94b9c335b94b2ca01ebb71f2da54747b9ee1)) +* **docs:** Update private voting tutorial cli commands ([#4472](https://github.com/AztecProtocol/aztec-packages/issues/4472)) ([0a8905a](https://github.com/AztecProtocol/aztec-packages/commit/0a8905a46fba47d1a773fd9cf562ef6f51197236)) +* Parse instance deployed event ([#4482](https://github.com/AztecProtocol/aztec-packages/issues/4482)) ([62b171a](https://github.com/AztecProtocol/aztec-packages/commit/62b171a1d217324fc61fad049ab32ce97a2fc2fb)) + + +### Miscellaneous + +* Able to run noir-sync manually ([#4486](https://github.com/AztecProtocol/aztec-packages/issues/4486)) ([2082fed](https://github.com/AztecProtocol/aztec-packages/commit/2082fedfb03d4882a269881f51c5337263bc539b)) +* **acir:** Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) [skip ci] ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Add bigint solver in ACVM and add a unit test for bigints in Noir (https://github.com/AztecProtocol/aztec-packages/pull/4415) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* **avm:** Add SET serialize comments and simplify signature ([#4476](https://github.com/AztecProtocol/aztec-packages/issues/4476)) ([84dbdd3](https://github.com/AztecProtocol/aztec-packages/commit/84dbdd35684ebc9929097c4ea9cfd59584fb8cbb)) +* Lift rollup address check & deplot kv-store to npm ([#4483](https://github.com/AztecProtocol/aztec-packages/issues/4483)) ([92d0aa4](https://github.com/AztecProtocol/aztec-packages/commit/92d0aa40ef9add4b433feed8862ba4286dc7036c)) +* Nuked `OptionallyRevealedData` ([#4456](https://github.com/AztecProtocol/aztec-packages/issues/4456)) ([83a3136](https://github.com/AztecProtocol/aztec-packages/commit/83a3136ac1553184b42ca7d96609697098eb80f4)) +* Rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Replace relative paths to noir-protocol-circuits ([902bbd4](https://github.com/AztecProtocol/aztec-packages/commit/902bbd4af8c77e209ad1f29e0fe03b55a384b142)) +* Surpress chained macro warning (https://github.com/AztecProtocol/aztec-packages/pull/4396) ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Sync to noir-lang/noir ([4113cfd](https://github.com/AztecProtocol/aztec-packages/commit/4113cfdfd5cf43a4dff98cdc398daf3a0d891dd3)) +* Unhardcode canonical addresses of deployer and registerer contracts ([#4467](https://github.com/AztecProtocol/aztec-packages/issues/4467)) ([2c82b62](https://github.com/AztecProtocol/aztec-packages/commit/2c82b62951ac001c4c1574b539aeff76d4e6d014)) + +## [0.22.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.21.0...aztec-packages-v0.22.0) (2024-02-06) + + +### ⚠ BREAKING CHANGES + +* rename bigint_neg into bigint_sub ([#4420](https://github.com/AztecProtocol/aztec-packages/issues/4420)) +* Add expression width into acir ([#4014](https://github.com/AztecProtocol/aztec-packages/issues/4014)) +* Use NoteSerialize and NoteDeserialize traits for note specific serialization ([#4383](https://github.com/AztecProtocol/aztec-packages/issues/4383)) +* Unencrypted logs are not strings ([#4392](https://github.com/AztecProtocol/aztec-packages/issues/4392)) +* init storage macro ([#4200](https://github.com/AztecProtocol/aztec-packages/issues/4200)) +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) +* introduce compute_note_hash_for_(consumption/insertion) ([#4344](https://github.com/AztecProtocol/aztec-packages/issues/4344)) +* replace Note::compute_note_hash with Note::compute_note_content_hash ([#4342](https://github.com/AztecProtocol/aztec-packages/issues/4342)) +* Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) +* Serialize, Deserialize and NoteInterface as Traits ([#4135](https://github.com/AztecProtocol/aztec-packages/issues/4135)) + +### Features + +* Add aztec node to client execution and nuke state info provider [#4320](https://github.com/AztecProtocol/aztec-packages/issues/4320) ([#4401](https://github.com/AztecProtocol/aztec-packages/issues/4401)) ([2dec0cc](https://github.com/AztecProtocol/aztec-packages/commit/2dec0cc4bf5bc592443d65e3a9923fc2a4f076a3)) +* Add bit size to const opcode ([#4385](https://github.com/AztecProtocol/aztec-packages/issues/4385)) ([b2a000e](https://github.com/AztecProtocol/aztec-packages/commit/b2a000e5f366721b514653456db804a704242b20)) +* Add expression width into acir ([#4014](https://github.com/AztecProtocol/aztec-packages/issues/4014)) ([f09e8fc](https://github.com/AztecProtocol/aztec-packages/commit/f09e8fc3fdaf9a0e5b9f927e345bf9e819e2024c)) +* Add meta_hwm to PrivateCircuitPublicInputs ([#4341](https://github.com/AztecProtocol/aztec-packages/issues/4341)) ([4f248b5](https://github.com/AztecProtocol/aztec-packages/commit/4f248b55af8119ed588754dff3cf14eb0559c8d2)) +* Add poseidon2 hashing to native transcript ([#3718](https://github.com/AztecProtocol/aztec-packages/issues/3718)) ([afcfa71](https://github.com/AztecProtocol/aztec-packages/commit/afcfa71da760680dfe02c39cf2de068a4297b3e7)) +* Adding slitherin detectors ([#4246](https://github.com/AztecProtocol/aztec-packages/issues/4246)) ([7cdc186](https://github.com/AztecProtocol/aztec-packages/commit/7cdc18692313017a70b9c8d761b7540eb96a9369)) +* Allow brillig to read arrays directly from memory ([#4460](https://github.com/AztecProtocol/aztec-packages/issues/4460)) ([f99392d](https://github.com/AztecProtocol/aztec-packages/commit/f99392dace572889b34ccd000f8af252c92c3b5e)) +* Allow using of current block in inclusion proofs ([#4285](https://github.com/AztecProtocol/aztec-packages/issues/4285)) ([728c5ac](https://github.com/AztecProtocol/aztec-packages/commit/728c5ac5dd534ce28c2ac84a8f720ea85c36308c)), closes [#4274](https://github.com/AztecProtocol/aztec-packages/issues/4274) +* **avm-transpiler:** Brillig to AVM transpiler ([#4227](https://github.com/AztecProtocol/aztec-packages/issues/4227)) ([c366c6e](https://github.com/AztecProtocol/aztec-packages/commit/c366c6e6d5c9f28a5dc92a303dcab4a23fb2d84e)) +* **avm:** Add command to call avm proving in bb binary ([#4369](https://github.com/AztecProtocol/aztec-packages/issues/4369)) ([4f6d607](https://github.com/AztecProtocol/aztec-packages/commit/4f6d607d7dce36819d84ba6ce69bbd57e0ad79a0)), closes [#4039](https://github.com/AztecProtocol/aztec-packages/issues/4039) +* **avm:** Add revert tracking to the journal ([#4349](https://github.com/AztecProtocol/aztec-packages/issues/4349)) ([1615803](https://github.com/AztecProtocol/aztec-packages/commit/161580312a753fb2f0507c11fb10d895b5073e3e)) +* **avm:** Back in avm context with macro - refactor context ([#4438](https://github.com/AztecProtocol/aztec-packages/issues/4438)) ([ccf9b17](https://github.com/AztecProtocol/aztec-packages/commit/ccf9b17495ec46df6494fa93e1c848c87a05d071)) +* **avm:** Complete SET instruction ([#4378](https://github.com/AztecProtocol/aztec-packages/issues/4378)) ([013891f](https://github.com/AztecProtocol/aztec-packages/commit/013891fc3a65066a315652ad0ac41a9622b59573)) +* **avm:** Implement avm state getter opcodes within noir contracts ([#4402](https://github.com/AztecProtocol/aztec-packages/issues/4402)) ([9f2a6eb](https://github.com/AztecProtocol/aztec-packages/commit/9f2a6eb80f796a9be1c9c5b6a143dc70e5ec3c43)) +* **avm:** Implement serialization for all existing operations ([#4338](https://github.com/AztecProtocol/aztec-packages/issues/4338)) ([13e0683](https://github.com/AztecProtocol/aztec-packages/commit/13e0683034e3a7ec02f73be36c82e5b3a9fe7151)) +* **avm:** Keep history of reads and writes in journal ([#4315](https://github.com/AztecProtocol/aztec-packages/issues/4315)) ([cdf1baf](https://github.com/AztecProtocol/aztec-packages/commit/cdf1baf017c4833bc621ba4dd3681dd1a745e259)) +* **aztec-nr:** Initial work for aztec public vm macro ([#4400](https://github.com/AztecProtocol/aztec-packages/issues/4400)) ([0024590](https://github.com/AztecProtocol/aztec-packages/commit/00245900d1cc7511f3fa71fe461944fbe7094d5a)) +* **bb:** Wasmtime and remote benchmarking ([#4204](https://github.com/AztecProtocol/aztec-packages/issues/4204)) ([fd27808](https://github.com/AztecProtocol/aztec-packages/commit/fd27808721b1f32b4828db5465b502cca2f1ce6c)) +* Contract class registerer contract ([#4403](https://github.com/AztecProtocol/aztec-packages/issues/4403)) ([d953090](https://github.com/AztecProtocol/aztec-packages/commit/d953090ca9eba0184d10c0b8ddbc60998bc155f0)), closes [#4069](https://github.com/AztecProtocol/aztec-packages/issues/4069) [#4070](https://github.com/AztecProtocol/aztec-packages/issues/4070) +* Crude stable var implementation ([#4289](https://github.com/AztecProtocol/aztec-packages/issues/4289)) ([5f9eee4](https://github.com/AztecProtocol/aztec-packages/commit/5f9eee48579a507512612e283b4106ddf9d72555)) +* **docs:** Docs deeper dive into unconstrained functions ([#4233](https://github.com/AztecProtocol/aztec-packages/issues/4233)) ([6af548e](https://github.com/AztecProtocol/aztec-packages/commit/6af548e369d5d20bcbd08d346f5c6f89b7363f39)) +* Emit single functions from class registerer ([#4429](https://github.com/AztecProtocol/aztec-packages/issues/4429)) ([19e03ad](https://github.com/AztecProtocol/aztec-packages/commit/19e03adc71ab7561d33dc9d75b9bdb7c19883fc9)), closes [#4427](https://github.com/AztecProtocol/aztec-packages/issues/4427) +* Extend Historical Access APIs [#4179](https://github.com/AztecProtocol/aztec-packages/issues/4179) ([#4375](https://github.com/AztecProtocol/aztec-packages/issues/4375)) ([c918d8d](https://github.com/AztecProtocol/aztec-packages/commit/c918d8d1a6ba306afd2feab97ddb8527b76d1a82)) +* Folding `GoblinUltra` instances in ProtoGalaxy ([#4340](https://github.com/AztecProtocol/aztec-packages/issues/4340)) ([8569e7c](https://github.com/AztecProtocol/aztec-packages/commit/8569e7c091c3db424a3f1c70b0749489d8574ad2)) +* Hashing output of `serialize()` in noir + more tests ([#4365](https://github.com/AztecProtocol/aztec-packages/issues/4365)) ([5a71bb9](https://github.com/AztecProtocol/aztec-packages/commit/5a71bb95a57bf22189e2611035e5f1faae92426b)) +* Implementation for bigint opcodes ([#4288](https://github.com/AztecProtocol/aztec-packages/issues/4288)) ([b61dace](https://github.com/AztecProtocol/aztec-packages/commit/b61dacee47f57a8fce6657f28b64e7a3128d0dba)) +* Improve ivc bench ([#4242](https://github.com/AztecProtocol/aztec-packages/issues/4242)) ([9d28354](https://github.com/AztecProtocol/aztec-packages/commit/9d28354ecefc9f7db71c7d2f40da7eae30e133c5)) +* Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) ([0ed4126](https://github.com/AztecProtocol/aztec-packages/commit/0ed41261ae43e21f695c35ad753e07adfaaa55f9)), closes [#4054](https://github.com/AztecProtocol/aztec-packages/issues/4054) +* Init storage macro ([#4200](https://github.com/AztecProtocol/aztec-packages/issues/4200)) ([11d9697](https://github.com/AztecProtocol/aztec-packages/commit/11d9697f8c1248e92341638a5587c7e24b09425a)) +* Memory only brillig ([#4215](https://github.com/AztecProtocol/aztec-packages/issues/4215)) ([018177b](https://github.com/AztecProtocol/aztec-packages/commit/018177bc757cce3258c153a56f1f7a871fec681c)) +* Nullified note retrieval in get_notes and view_notes ([#4238](https://github.com/AztecProtocol/aztec-packages/issues/4238)) ([8d02eb7](https://github.com/AztecProtocol/aztec-packages/commit/8d02eb71c96eb01726ec828e0e6934d0f30121ed)) +* Private calls and initialization of undeployed contracts ([#4362](https://github.com/AztecProtocol/aztec-packages/issues/4362)) ([f31c181](https://github.com/AztecProtocol/aztec-packages/commit/f31c181f187c2aca90c91834a434b7d2e563af84)), closes [#4057](https://github.com/AztecProtocol/aztec-packages/issues/4057) [#4058](https://github.com/AztecProtocol/aztec-packages/issues/4058) [#4059](https://github.com/AztecProtocol/aztec-packages/issues/4059) +* Revert early in verifier contract for malformed proof inputs ([#4453](https://github.com/AztecProtocol/aztec-packages/issues/4453)) ([d4a7716](https://github.com/AztecProtocol/aztec-packages/commit/d4a7716800a5f67ec55f7f85beeb439f11b11d4d)) +* Sequencer processes transactions in phases ([#4345](https://github.com/AztecProtocol/aztec-packages/issues/4345)) ([78cc709](https://github.com/AztecProtocol/aztec-packages/commit/78cc709ea5f9fc137472a76e5155216ca439d292)) +* Unencrypted logs are not strings ([#4392](https://github.com/AztecProtocol/aztec-packages/issues/4392)) ([25a7ea7](https://github.com/AztecProtocol/aztec-packages/commit/25a7ea76effa98b09051cde383fdcce95e314166)) +* Validate verification key on contract deployment ([#4450](https://github.com/AztecProtocol/aztec-packages/issues/4450)) ([00f9966](https://github.com/AztecProtocol/aztec-packages/commit/00f996631130b9a284f29adff4ce5bcc5ad70b1b)) +* Verify function against contract class id in private kernel ([#4337](https://github.com/AztecProtocol/aztec-packages/issues/4337)) ([e1d832d](https://github.com/AztecProtocol/aztec-packages/commit/e1d832dbf6bf06b192538bc768871848484a4f14)), closes [#4056](https://github.com/AztecProtocol/aztec-packages/issues/4056) + + +### Bug Fixes + +* **avm-transpiler:** Avm-transpiler bootstrap by tying down rust version ([#4347](https://github.com/AztecProtocol/aztec-packages/issues/4347)) ([09d0730](https://github.com/AztecProtocol/aztec-packages/commit/09d0730bad4be2f4954cbb6d27538f7860d0f21f)) +* **avm-transpiler:** Bump rust toolchain version for transpiler ([#4356](https://github.com/AztecProtocol/aztec-packages/issues/4356)) ([75e30b9](https://github.com/AztecProtocol/aztec-packages/commit/75e30b999feeda0f7526669f3f0f08ca6c4acac2)) +* **avm:** Fix SendL2ToL1Message implementation ([#4367](https://github.com/AztecProtocol/aztec-packages/issues/4367)) ([ee560c3](https://github.com/AztecProtocol/aztec-packages/commit/ee560c32873a085a68288357471b1a54d8cb9c6f)) +* Aztec binary fixes ([#4273](https://github.com/AztecProtocol/aztec-packages/issues/4273)) ([84e1f7d](https://github.com/AztecProtocol/aztec-packages/commit/84e1f7dd0e005351bb742b015270ab2fd575136d)) +* Bb build ([#4317](https://github.com/AztecProtocol/aztec-packages/issues/4317)) ([82f5f03](https://github.com/AztecProtocol/aztec-packages/commit/82f5f03acdaee8e23b149369cb9e6f89f257b757)) +* **docs:** Another one ([#4455](https://github.com/AztecProtocol/aztec-packages/issues/4455)) ([538f308](https://github.com/AztecProtocol/aztec-packages/commit/538f3081f7ac158d983e182ce848254f63335740)) +* **docs:** Update import ([#4451](https://github.com/AztecProtocol/aztec-packages/issues/4451)) ([a4bc954](https://github.com/AztecProtocol/aztec-packages/commit/a4bc954006269fd064d76300aa515604a6bbdd29)) +* Load contract artifact from json ([#4352](https://github.com/AztecProtocol/aztec-packages/issues/4352)) ([47a0a79](https://github.com/AztecProtocol/aztec-packages/commit/47a0a79f6beaa241eafc94fcae84103488a9dcef)) +* Mac build ([#4336](https://github.com/AztecProtocol/aztec-packages/issues/4336)) ([aeb4cf0](https://github.com/AztecProtocol/aztec-packages/commit/aeb4cf0d9cec6127cac947c4f0de8e853b2f34e0)) +* **noir-contracts:** Disable transpilation for now ([#4372](https://github.com/AztecProtocol/aztec-packages/issues/4372)) ([37662b7](https://github.com/AztecProtocol/aztec-packages/commit/37662b78da3811fd5d5f4d4d33d69d4c5fd873e3)) +* Nr codegen to use new protocol types path ([#4353](https://github.com/AztecProtocol/aztec-packages/issues/4353)) ([84e63b1](https://github.com/AztecProtocol/aztec-packages/commit/84e63b12dcc45130ddef499dca383b09c9844b8b)), closes [#4193](https://github.com/AztecProtocol/aztec-packages/issues/4193) +* Relative LogFn import ([#4328](https://github.com/AztecProtocol/aztec-packages/issues/4328)) ([1faead5](https://github.com/AztecProtocol/aztec-packages/commit/1faead5bf5e07417e2d4452a2e3ff096a273a41a)) +* Release the size of goblin translator ([#4259](https://github.com/AztecProtocol/aztec-packages/issues/4259)) ([6e1d958](https://github.com/AztecProtocol/aztec-packages/commit/6e1d958badafdbe4abdc0c221047186c5da69be4)) +* Transpiler build ([#4386](https://github.com/AztecProtocol/aztec-packages/issues/4386)) ([032ddc5](https://github.com/AztecProtocol/aztec-packages/commit/032ddc53840e79b3f324b99b82f0aebfa3c83bfe)) + + +### Miscellaneous + +* `PublicCircuitPublicInputs` and `PrivateCircuitPublicInputs` cleanup ([#4360](https://github.com/AztecProtocol/aztec-packages/issues/4360)) ([b92d690](https://github.com/AztecProtocol/aztec-packages/commit/b92d6904fc9ad2cda30de1245fd546e00a5523e1)) +* `toFields()`/`fromFields(...)` methods in more classes ([#4335](https://github.com/AztecProtocol/aztec-packages/issues/4335)) ([433b9eb](https://github.com/AztecProtocol/aztec-packages/commit/433b9ebdb505b21bef40c174e4feec0e6ca211e8)) +* Acir-simulator -> simulator ([#4439](https://github.com/AztecProtocol/aztec-packages/issues/4439)) ([bccd809](https://github.com/AztecProtocol/aztec-packages/commit/bccd809183f18a0d6fc05bfcdffa78ba1169e894)) +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) ([9c965a7](https://github.com/AztecProtocol/aztec-packages/commit/9c965a7c9e652dfeaba2f09152e5db287407473d)) +* Add bigint solver in ACVM and add a unit test for bigints in Noir ([#4415](https://github.com/AztecProtocol/aztec-packages/issues/4415)) ([e4a2fe9](https://github.com/AztecProtocol/aztec-packages/commit/e4a2fe906f5e02ebcc1fc7a8b7a5d96f3b11fcb5)) +* Add bootstrap_cache for avm-transpiler ([#4357](https://github.com/AztecProtocol/aztec-packages/issues/4357)) ([bfebebb](https://github.com/AztecProtocol/aztec-packages/commit/bfebebb89fc9a9b87f19237642cec9a221abf712)) +* Add disclaimer ([#4393](https://github.com/AztecProtocol/aztec-packages/issues/4393)) ([6895f52](https://github.com/AztecProtocol/aztec-packages/commit/6895f522220ee689acb178a9ee6271b132fd6cd0)) +* Add migration note for serialization change ([#4414](https://github.com/AztecProtocol/aztec-packages/issues/4414)) ([968a3a0](https://github.com/AztecProtocol/aztec-packages/commit/968a3a0734c202cccec5f322a0dd272f66cbeb1c)) +* **avm:** Make interpreter a function not a class ([#4272](https://github.com/AztecProtocol/aztec-packages/issues/4272)) ([14e8c5c](https://github.com/AztecProtocol/aztec-packages/commit/14e8c5c325ad8459e3c81cc7e443ca277dd072a9)) +* **avm:** Refactor AVM Simulator and fix issues ([#4424](https://github.com/AztecProtocol/aztec-packages/issues/4424)) ([a6179bd](https://github.com/AztecProtocol/aztec-packages/commit/a6179bdb52070d71dd04a3721f987a89920f4d98)) +* Call stack item cleanup ([#4381](https://github.com/AztecProtocol/aztec-packages/issues/4381)) ([341b0a1](https://github.com/AztecProtocol/aztec-packages/commit/341b0a177f35d2e46d9f3e011f1543a20628244b)) +* Check loading Nargo artifacts works in the cli ([#4355](https://github.com/AztecProtocol/aztec-packages/issues/4355)) ([43b58b3](https://github.com/AztecProtocol/aztec-packages/commit/43b58b346cd788cc4bfa187626bf53b518ad5bb4)) +* Cleanup + various doc improvements ([#4282](https://github.com/AztecProtocol/aztec-packages/issues/4282)) ([648229c](https://github.com/AztecProtocol/aztec-packages/commit/648229c24e01b2eeeeb0b361b65c0d62c0adf8ea)), closes [#4264](https://github.com/AztecProtocol/aztec-packages/issues/4264) +* Collapse bb::honk ([#4318](https://github.com/AztecProtocol/aztec-packages/issues/4318)) ([5853af4](https://github.com/AztecProtocol/aztec-packages/commit/5853af448a86ed02901609f4786e86fe1651880e)) +* Consistent naming of serialization method ([#4379](https://github.com/AztecProtocol/aztec-packages/issues/4379)) ([148d5dc](https://github.com/AztecProtocol/aztec-packages/commit/148d5dc754329eabcc42430b4ee06993ec2d4224)) +* Do not run forge fmt because not everyone has forge installed ([#4430](https://github.com/AztecProtocol/aztec-packages/issues/4430)) ([ecb6c3f](https://github.com/AztecProtocol/aztec-packages/commit/ecb6c3fdff93e8c194acaef9de45d8e740a14bb0)) +* **docs:** Update broken link ref in slow_updates_tree.md ([#4339](https://github.com/AztecProtocol/aztec-packages/issues/4339)) ([2599d7f](https://github.com/AztecProtocol/aztec-packages/commit/2599d7f1ea3f616375a7d439c8bde016b6f2b876)) +* **docs:** Updating concepts/communication pages images ([#4368](https://github.com/AztecProtocol/aztec-packages/issues/4368)) ([92fb2b0](https://github.com/AztecProtocol/aztec-packages/commit/92fb2b091d6a6143d5f736c4e1e15e454f14a162)), closes [#3857](https://github.com/AztecProtocol/aztec-packages/issues/3857) +* Eth address tech debt cleanup ([#4442](https://github.com/AztecProtocol/aztec-packages/issues/4442)) ([153989f](https://github.com/AztecProtocol/aztec-packages/commit/153989f636b0b76522597fdf60e1f2af9e318b10)) +* Extract merge from UC and simplify ([#4343](https://github.com/AztecProtocol/aztec-packages/issues/4343)) ([54fd794](https://github.com/AztecProtocol/aztec-packages/commit/54fd7949cdbb0e213c37ce331f7546e2827f4c17)) +* Fix bb wasm build when using remote cache ([#4397](https://github.com/AztecProtocol/aztec-packages/issues/4397)) ([14e57cb](https://github.com/AztecProtocol/aztec-packages/commit/14e57cb285571208c5f88f0eaf500b1e7859ef04)) +* Fix clippy warnings in `avm-transpiler` ([#4416](https://github.com/AztecProtocol/aztec-packages/issues/4416)) ([e54ecd2](https://github.com/AztecProtocol/aztec-packages/commit/e54ecd25ad375901eee859f4a85745b5047c190f)) +* Fix some circular imports ([#4445](https://github.com/AztecProtocol/aztec-packages/issues/4445)) ([e6a9c68](https://github.com/AztecProtocol/aztec-packages/commit/e6a9c68148deffb6a1352cf2ed75281568ebef39)) +* Format l1-contracts after generating constants ([#4448](https://github.com/AztecProtocol/aztec-packages/issues/4448)) ([de11994](https://github.com/AztecProtocol/aztec-packages/commit/de11994d19e84b641984b198c594592147d9c2ec)) +* Git subrepo commit (merge) noir ([#4321](https://github.com/AztecProtocol/aztec-packages/issues/4321)) ([348d18a](https://github.com/AztecProtocol/aztec-packages/commit/348d18aa3c864fc80fc791029b2d91ee9e7e33d4)) +* Git subrepo pull (merge) noir ([#4331](https://github.com/AztecProtocol/aztec-packages/issues/4331)) ([683f782](https://github.com/AztecProtocol/aztec-packages/commit/683f782e08b007f82505c19f093eed12cd5f48eb)) +* Implementing `deserialize()` in Noir structs ([#4384](https://github.com/AztecProtocol/aztec-packages/issues/4384)) ([e63bbae](https://github.com/AztecProtocol/aztec-packages/commit/e63bbaefebb9f0048eb9b2c80ea392bfd86831c1)) +* Introduce compute_note_hash_for_(consumption/insertion) ([#4344](https://github.com/AztecProtocol/aztec-packages/issues/4344)) ([26a0d49](https://github.com/AztecProtocol/aztec-packages/commit/26a0d49de177a1e7faecc4dede453de4c46808bb)) +* Optimize prove_note_validity [#4418](https://github.com/AztecProtocol/aztec-packages/issues/4418) ([#4426](https://github.com/AztecProtocol/aztec-packages/issues/4426)) ([4de2540](https://github.com/AztecProtocol/aztec-packages/commit/4de25403b4bbdabbd0bfef84ae8a685be682bf84)) +* Poseidon2 hash uses span instead of vector ([#4003](https://github.com/AztecProtocol/aztec-packages/issues/4003)) ([f63e7a9](https://github.com/AztecProtocol/aztec-packages/commit/f63e7a94b1ba555eecbe08b7114e8b6ad0b82bc0)) +* Reenable private kernel function tree checks ([#4358](https://github.com/AztecProtocol/aztec-packages/issues/4358)) ([e7db0da](https://github.com/AztecProtocol/aztec-packages/commit/e7db0da2a055567e859b347bba30c3cc18f32f68)) +* Remove hardcoded storage slot values ([#4398](https://github.com/AztecProtocol/aztec-packages/issues/4398)) ([d2294a4](https://github.com/AztecProtocol/aztec-packages/commit/d2294a4d58e76a7bc9be8f153b47a5a5d5d87db1)) +* Rename bigint_neg into bigint_sub ([#4420](https://github.com/AztecProtocol/aztec-packages/issues/4420)) ([57824fe](https://github.com/AztecProtocol/aztec-packages/commit/57824feff268153a7a33b90a3dc68d5bc98a2471)) +* Replace Note::compute_note_hash with Note::compute_note_content_hash ([#4342](https://github.com/AztecProtocol/aztec-packages/issues/4342)) ([8368659](https://github.com/AztecProtocol/aztec-packages/commit/836865983c2a0bc6878bde1e30dca56f97f9e1a2)) +* Replace relative paths to noir-protocol-circuits ([23de650](https://github.com/AztecProtocol/aztec-packages/commit/23de6504f02b0f93799f57d41b5b4e005e227228)) +* Replace relative paths to noir-protocol-circuits ([b8d427f](https://github.com/AztecProtocol/aztec-packages/commit/b8d427fbd735f586c2ea4101e00aa57bc24814aa)) +* Replace relative paths to noir-protocol-circuits ([113dec1](https://github.com/AztecProtocol/aztec-packages/commit/113dec1c00293b79aacc506dd6cdfd976a46bcc7)) +* Replace relative paths to noir-protocol-circuits ([a79093b](https://github.com/AztecProtocol/aztec-packages/commit/a79093bc9c43efd6c8e1c4c2ceb19d39284e914e)) +* Replace relative paths to noir-protocol-circuits ([808b4eb](https://github.com/AztecProtocol/aztec-packages/commit/808b4eb21b74df2b352b571f2f93e949036bd626)) +* Serialize, Deserialize and NoteInterface as Traits ([#4135](https://github.com/AztecProtocol/aztec-packages/issues/4135)) ([9e6605c](https://github.com/AztecProtocol/aztec-packages/commit/9e6605cf7cc6e778b681e4e0c39788ab58249f55)) +* Simpler noir sync ([#4376](https://github.com/AztecProtocol/aztec-packages/issues/4376)) ([665b35e](https://github.com/AztecProtocol/aztec-packages/commit/665b35ea1f667be057df3d6bb2ca26beb8f3b461)) +* Surpress chained macro warning ([#4396](https://github.com/AztecProtocol/aztec-packages/issues/4396)) ([5e9c790](https://github.com/AztecProtocol/aztec-packages/commit/5e9c79057ff7e372c71e221756fc7577aa06baeb)) +* Switch to macos-14 for m1 runners ([#3456](https://github.com/AztecProtocol/aztec-packages/issues/3456)) ([ca5b6f8](https://github.com/AztecProtocol/aztec-packages/commit/ca5b6f8b23adf78dbc8c76f08514edeaa3eebfab)) +* Testing `toFields()` length ([#4364](https://github.com/AztecProtocol/aztec-packages/issues/4364)) ([5d3fce3](https://github.com/AztecProtocol/aztec-packages/commit/5d3fce35a51151eddde6982913c5d4bd865e450d)) +* Typing contents of `MessageLoadOracleInputs` ([#4351](https://github.com/AztecProtocol/aztec-packages/issues/4351)) ([433babd](https://github.com/AztecProtocol/aztec-packages/commit/433babdadfc3fa5e14634e43aafb9efd9c3c2313)) +* Update docs for historical state ([#4461](https://github.com/AztecProtocol/aztec-packages/issues/4461)) ([16a2eca](https://github.com/AztecProtocol/aztec-packages/commit/16a2eca1dbc5e8f4ca99c46363ed00eaa54dc97e)) +* Update docs on comparators ([#4281](https://github.com/AztecProtocol/aztec-packages/issues/4281)) ([cc2ce9c](https://github.com/AztecProtocol/aztec-packages/commit/cc2ce9c012a11206bd2528771774aa817fa7a922)) +* Updating block hash to be header.hash() ([#4286](https://github.com/AztecProtocol/aztec-packages/issues/4286)) ([d4125e1](https://github.com/AztecProtocol/aztec-packages/commit/d4125e12459a0375e9fa2cb8b83f700654219cea)) +* Use NoteSerialize and NoteDeserialize traits for note specific serialization ([#4383](https://github.com/AztecProtocol/aztec-packages/issues/4383)) ([14dd0b8](https://github.com/AztecProtocol/aztec-packages/commit/14dd0b885721d4b9024ceb6569e929269ec9ad23)) + + +### Documentation + +* Add simple api description for note_getter_options.status ([#4329](https://github.com/AztecProtocol/aztec-packages/issues/4329)) ([cc17afe](https://github.com/AztecProtocol/aztec-packages/commit/cc17afe73da1f2cad18080797f30210908caa7f6)) +* Document stable public state usage ([#4324](https://github.com/AztecProtocol/aztec-packages/issues/4324)) ([13f709b](https://github.com/AztecProtocol/aztec-packages/commit/13f709b2b94d17af34da2e609c2b764977eb5d6b)), closes [#4325](https://github.com/AztecProtocol/aztec-packages/issues/4325) +* Minor quickstart fixes ([#4330](https://github.com/AztecProtocol/aztec-packages/issues/4330)) ([f85a870](https://github.com/AztecProtocol/aztec-packages/commit/f85a87084e3fdba20b6f74d7e53b2e95925e8548)) +* Update contract deployment section in YP ([#4290](https://github.com/AztecProtocol/aztec-packages/issues/4290)) ([e99a882](https://github.com/AztecProtocol/aztec-packages/commit/e99a882fcc69041a34ecd7febafe46d661b76094)) +* **yellow-paper:** Update kernel with changes from contract deployment ([#4432](https://github.com/AztecProtocol/aztec-packages/issues/4432)) ([201a80e](https://github.com/AztecProtocol/aztec-packages/commit/201a80e747d3754dc2d20c25d4a2c10cc0847f9e)) +* **yp:** AVM circuit - user memory section ([#4323](https://github.com/AztecProtocol/aztec-packages/issues/4323)) ([8928fb1](https://github.com/AztecProtocol/aztec-packages/commit/8928fb1f46ce6403eb425548d254e8cfbb6ae6a9)), closes [#4043](https://github.com/AztecProtocol/aztec-packages/issues/4043) + ## [0.21.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.20.0...aztec-packages-v0.21.0) (2024-01-30) diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index 718f61220a5..b571e5ffbd4 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -317,6 +317,7 @@ dependencies = [ name = "aztec_macros" version = "0.23.0" dependencies = [ + "convert_case", "iter-extended", "noirc_frontend", ] @@ -550,6 +551,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -1775,6 +1785,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "unicode-width" version = "0.1.11" diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index 198b327f8e3..bf34f64dc21 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -1,4 +1,4 @@ -use std::fmt; +use std::fmt::{self, Display}; use std::fmt::{Debug, Formatter}; use crate::opcodes::AvmOpcode; @@ -28,26 +28,29 @@ pub struct AvmInstruction { /// Different instructions have different numbers of operands pub operands: Vec, } -impl AvmInstruction { - /// String representation for printing AVM programs - pub fn to_string(&self) -> String { - let mut out_str = format!("opcode {}", self.opcode.name()); + +impl Display for AvmInstruction { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "opcode {}", self.opcode.name())?; if let Some(indirect) = self.indirect { - out_str += format!(", indirect: {}", indirect).as_str(); + write!(f, ", indirect: {}", indirect)?; } // TODO(4271): add in_tag alongside its support in TS if let Some(dst_tag) = self.dst_tag { - out_str += format!(", dst_tag: {}", dst_tag as u8).as_str(); + write!(f, ", dst_tag: {}", dst_tag as u8)?; } if !self.operands.is_empty() { - out_str += ", operands: ["; + write!(f, ", operands: [")?; for operand in &self.operands { - out_str += format!("{}, ", operand.to_string()).as_str(); + write!(f, "{operand}, ")?; } - out_str += "]"; - } - out_str + write!(f, "]")?; + }; + Ok(()) } +} + +impl AvmInstruction { /// Bytes representation for generating AVM bytecode pub fn to_bytes(&self) -> Vec { let mut bytes = Vec::new(); @@ -69,7 +72,7 @@ impl AvmInstruction { impl Debug for AvmInstruction { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.to_string()) + write!(f, "{self}") } } @@ -106,14 +109,18 @@ pub enum AvmOperand { // TODO(4267): Support operands of size other than 32 bits (for SET) U128 { value: u128 }, } -impl AvmOperand { - pub fn to_string(&self) -> String { + +impl Display for AvmOperand { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - AvmOperand::U32 { value } => format!(" U32:{}", value), + AvmOperand::U32 { value } => write!(f, " U32:{}", value), // TODO(4267): Support operands of size other than 32 bits (for SET) - AvmOperand::U128 { value } => format!(" U128:{}", value), + AvmOperand::U128 { value } => write!(f, " U128:{}", value), } } +} + +impl AvmOperand { pub fn to_be_bytes(&self) -> Vec { match self { AvmOperand::U32 { value } => value.to_be_bytes().to_vec(), diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index e4f112f9ee8..62dceb654c6 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -1,7 +1,7 @@ use acvm::acir::brillig::Opcode as BrilligOpcode; use acvm::acir::circuit::brillig::Brillig; -use acvm::brillig_vm::brillig::{BinaryFieldOp, BinaryIntOp}; +use acvm::brillig_vm::brillig::{BinaryFieldOp, BinaryIntOp, ValueOrArray}; use crate::instructions::{ AvmInstruction, AvmOperand, AvmTypeTag, FIRST_OPERAND_INDIRECT, ZEROTH_OPERAND_INDIRECT, @@ -141,7 +141,7 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { ..Default::default() }); } - BrilligOpcode::Const { destination, value } => { + BrilligOpcode::Const { destination, value, bit_size:_ } => { avm_instrs.push(AvmInstruction { opcode: AvmOpcode::SET, indirect: Some(0), @@ -252,7 +252,10 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { ], ..Default::default() }); - } + }, + BrilligOpcode::ForeignCall { function, destinations, inputs, destination_value_types:_, input_value_types:_ } => { + handle_foreign_call(&mut avm_instrs, function, destinations, inputs); + }, _ => panic!( "Transpiler doesn't know how to process {:?} brillig instruction", brillig_instr @@ -270,6 +273,54 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { bytecode } +/// Handle foreign function calls +/// - Environment getting opcodes will be represented as foreign calls +/// - TODO: support for avm external calls through this function +fn handle_foreign_call( + avm_instrs: &mut Vec, + function: &String, + destinations: &Vec, + inputs: &Vec, +) { + // For the foreign calls we want to handle, we do not want inputs, as they are getters + assert!(inputs.len() == 0); + assert!(destinations.len() == 1); + let dest_offset_maybe = destinations[0]; + let dest_offset = match dest_offset_maybe { + ValueOrArray::MemoryAddress(dest_offset) => dest_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let opcode = match function.as_str() { + "address" => AvmOpcode::ADDRESS, + "storageAddress" => AvmOpcode::STORAGEADDRESS, + "origin" => AvmOpcode::ORIGIN, + "sender" => AvmOpcode::SENDER, + "portal" => AvmOpcode::PORTAL, + "feePerL1Gas" => AvmOpcode::FEEPERL1GAS, + "feePerL2Gas" => AvmOpcode::FEEPERL2GAS, + "feePerDaGas" => AvmOpcode::FEEPERDAGAS, + "chainId" => AvmOpcode::CHAINID, + "version" => AvmOpcode::VERSION, + "blockNumber" => AvmOpcode::BLOCKNUMBER, + "timestamp" => AvmOpcode::TIMESTAMP, + // "callStackDepth" => AvmOpcode::CallStackDepth, + _ => panic!( + "Transpiler doesn't know how to process ForeignCall function {:?}", + function + ), + }; + + avm_instrs.push(AvmInstruction { + opcode, + indirect: Some(0), + operands: vec![AvmOperand::U32 { + value: dest_offset as u32, + }], + ..Default::default() + }); +} + /// Compute an array that maps each Brillig pc to an AVM pc. /// This must be done before transpiling to properly transpile jump destinations. /// This is necessary for two reasons: diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index 9b342b4d870..bcf848ab88e 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -1,3 +1,4 @@ +use base64::Engine; use log::info; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -101,7 +102,7 @@ impl From for TranspiledContract { function_type: function.function_type, is_internal: function.is_internal, abi: function.abi, - bytecode: base64::encode(avm_bytecode), + bytecode: base64::prelude::BASE64_STANDARD.encode(avm_bytecode), debug_symbols: function.debug_symbols, })); } else { diff --git a/aztec-up/bin/aztec-install b/aztec-up/bin/aztec-install index 3c7dec94844..769ed5fcb8c 100755 --- a/aztec-up/bin/aztec-install +++ b/aztec-up/bin/aztec-install @@ -90,7 +90,6 @@ fi # Create a "hidden" `$HOME/.aztec` dir, so as not to clutter the user's cwd. mkdir -p $AZTEC_PATH mkdir -p $BIN_PATH -rm -f $BIN_PATH/aztec* # Download containers from dockerhub. Tag them as latest. function pull_container { @@ -121,6 +120,7 @@ function install_bin { } info "Installing scripts in $BIN_PATH..." +rm -f $BIN_PATH/aztec* install_bin .aztec-run install_bin aztec install_bin aztec-cli diff --git a/barretenberg/.gitrepo b/barretenberg/.gitrepo index 1882483327a..e26a24052ff 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = a3cbcd73fe9a61a3d45712e99e0c68a79e83d730 - parent = 00245900d1cc7511f3fa71fe461944fbe7094d5a + commit = e8943ffc1a60c2c8ac368f32ce3c296f7a6dc566 + parent = e78b86f9d25cef977b4a3790cccd37a079c8a90f method = merge cmdver = 0.4.6 diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index 351958744a9..7fce1d30f4b 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,58 @@ # Changelog +## [0.23.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.22.0...barretenberg-v0.23.0) (2024-02-07) + + +### Features + +* Add additional error types to verifier contract and revert early ([#4464](https://github.com/AztecProtocol/aztec-packages/issues/4464)) ([5e16063](https://github.com/AztecProtocol/aztec-packages/commit/5e160632bb7d48e676583e1b62b604c25fc4af4e)) +* Allow nested arrays and vectors in Brillig foreign calls ([#4478](https://github.com/AztecProtocol/aztec-packages/issues/4478)) ([bbfa337](https://github.com/AztecProtocol/aztec-packages/commit/bbfa3374d20b44c49870e21c61cbb2ab5f7ae117)) +* **avm:** Generic bytecode deserialization ([#4441](https://github.com/AztecProtocol/aztec-packages/issues/4441)) ([934fabc](https://github.com/AztecProtocol/aztec-packages/commit/934fabc8d3706e601eb3dca546c4545b58a10006)), closes [#4304](https://github.com/AztecProtocol/aztec-packages/issues/4304) +* **bb:** Op counting mode ([#4437](https://github.com/AztecProtocol/aztec-packages/issues/4437)) ([5d00cff](https://github.com/AztecProtocol/aztec-packages/commit/5d00cff86a1f76f5279dad6a0bd4e02c8211b225)) + +## [0.22.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.21.0...barretenberg-v0.22.0) (2024-02-06) + + +### ⚠ BREAKING CHANGES + +* rename bigint_neg into bigint_sub ([#4420](https://github.com/AztecProtocol/aztec-packages/issues/4420)) +* Add expression width into acir ([#4014](https://github.com/AztecProtocol/aztec-packages/issues/4014)) +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) + +### Features + +* Add bit size to const opcode ([#4385](https://github.com/AztecProtocol/aztec-packages/issues/4385)) ([b2a000e](https://github.com/AztecProtocol/aztec-packages/commit/b2a000e5f366721b514653456db804a704242b20)) +* Add expression width into acir ([#4014](https://github.com/AztecProtocol/aztec-packages/issues/4014)) ([f09e8fc](https://github.com/AztecProtocol/aztec-packages/commit/f09e8fc3fdaf9a0e5b9f927e345bf9e819e2024c)) +* Add poseidon2 hashing to native transcript ([#3718](https://github.com/AztecProtocol/aztec-packages/issues/3718)) ([afcfa71](https://github.com/AztecProtocol/aztec-packages/commit/afcfa71da760680dfe02c39cf2de068a4297b3e7)) +* Allow brillig to read arrays directly from memory ([#4460](https://github.com/AztecProtocol/aztec-packages/issues/4460)) ([f99392d](https://github.com/AztecProtocol/aztec-packages/commit/f99392dace572889b34ccd000f8af252c92c3b5e)) +* **avm:** Add command to call avm proving in bb binary ([#4369](https://github.com/AztecProtocol/aztec-packages/issues/4369)) ([4f6d607](https://github.com/AztecProtocol/aztec-packages/commit/4f6d607d7dce36819d84ba6ce69bbd57e0ad79a0)), closes [#4039](https://github.com/AztecProtocol/aztec-packages/issues/4039) +* **avm:** Back in avm context with macro - refactor context ([#4438](https://github.com/AztecProtocol/aztec-packages/issues/4438)) ([ccf9b17](https://github.com/AztecProtocol/aztec-packages/commit/ccf9b17495ec46df6494fa93e1c848c87a05d071)) +* **bb:** Wasmtime and remote benchmarking ([#4204](https://github.com/AztecProtocol/aztec-packages/issues/4204)) ([fd27808](https://github.com/AztecProtocol/aztec-packages/commit/fd27808721b1f32b4828db5465b502cca2f1ce6c)) +* Folding `GoblinUltra` instances in ProtoGalaxy ([#4340](https://github.com/AztecProtocol/aztec-packages/issues/4340)) ([8569e7c](https://github.com/AztecProtocol/aztec-packages/commit/8569e7c091c3db424a3f1c70b0749489d8574ad2)) +* Implementation for bigint opcodes ([#4288](https://github.com/AztecProtocol/aztec-packages/issues/4288)) ([b61dace](https://github.com/AztecProtocol/aztec-packages/commit/b61dacee47f57a8fce6657f28b64e7a3128d0dba)) +* Improve ivc bench ([#4242](https://github.com/AztecProtocol/aztec-packages/issues/4242)) ([9d28354](https://github.com/AztecProtocol/aztec-packages/commit/9d28354ecefc9f7db71c7d2f40da7eae30e133c5)) +* Memory only brillig ([#4215](https://github.com/AztecProtocol/aztec-packages/issues/4215)) ([018177b](https://github.com/AztecProtocol/aztec-packages/commit/018177bc757cce3258c153a56f1f7a871fec681c)) +* Revert early in verifier contract for malformed proof inputs ([#4453](https://github.com/AztecProtocol/aztec-packages/issues/4453)) ([d4a7716](https://github.com/AztecProtocol/aztec-packages/commit/d4a7716800a5f67ec55f7f85beeb439f11b11d4d)) +* Validate verification key on contract deployment ([#4450](https://github.com/AztecProtocol/aztec-packages/issues/4450)) ([00f9966](https://github.com/AztecProtocol/aztec-packages/commit/00f996631130b9a284f29adff4ce5bcc5ad70b1b)) + + +### Bug Fixes + +* Bb build ([#4317](https://github.com/AztecProtocol/aztec-packages/issues/4317)) ([82f5f03](https://github.com/AztecProtocol/aztec-packages/commit/82f5f03acdaee8e23b149369cb9e6f89f257b757)) +* Mac build ([#4336](https://github.com/AztecProtocol/aztec-packages/issues/4336)) ([aeb4cf0](https://github.com/AztecProtocol/aztec-packages/commit/aeb4cf0d9cec6127cac947c4f0de8e853b2f34e0)) +* Release the size of goblin translator ([#4259](https://github.com/AztecProtocol/aztec-packages/issues/4259)) ([6e1d958](https://github.com/AztecProtocol/aztec-packages/commit/6e1d958badafdbe4abdc0c221047186c5da69be4)) + + +### Miscellaneous + +* Acir-simulator -> simulator ([#4439](https://github.com/AztecProtocol/aztec-packages/issues/4439)) ([bccd809](https://github.com/AztecProtocol/aztec-packages/commit/bccd809183f18a0d6fc05bfcdffa78ba1169e894)) +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) ([9c965a7](https://github.com/AztecProtocol/aztec-packages/commit/9c965a7c9e652dfeaba2f09152e5db287407473d)) +* Collapse bb::honk ([#4318](https://github.com/AztecProtocol/aztec-packages/issues/4318)) ([5853af4](https://github.com/AztecProtocol/aztec-packages/commit/5853af448a86ed02901609f4786e86fe1651880e)) +* Extract merge from UC and simplify ([#4343](https://github.com/AztecProtocol/aztec-packages/issues/4343)) ([54fd794](https://github.com/AztecProtocol/aztec-packages/commit/54fd7949cdbb0e213c37ce331f7546e2827f4c17)) +* Fix bb wasm build when using remote cache ([#4397](https://github.com/AztecProtocol/aztec-packages/issues/4397)) ([14e57cb](https://github.com/AztecProtocol/aztec-packages/commit/14e57cb285571208c5f88f0eaf500b1e7859ef04)) +* Poseidon2 hash uses span instead of vector ([#4003](https://github.com/AztecProtocol/aztec-packages/issues/4003)) ([f63e7a9](https://github.com/AztecProtocol/aztec-packages/commit/f63e7a94b1ba555eecbe08b7114e8b6ad0b82bc0)) +* Rename bigint_neg into bigint_sub ([#4420](https://github.com/AztecProtocol/aztec-packages/issues/4420)) ([57824fe](https://github.com/AztecProtocol/aztec-packages/commit/57824feff268153a7a33b90a3dc68d5bc98a2471)) + ## [0.21.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.20.0...barretenberg-v0.21.0) (2024-01-30) diff --git a/barretenberg/barretenberg.code-workspace b/barretenberg/barretenberg.code-workspace index 24c8a186612..362ddc1783c 100644 --- a/barretenberg/barretenberg.code-workspace +++ b/barretenberg/barretenberg.code-workspace @@ -152,8 +152,7 @@ }, "cmake.configureArgs": [ "--preset clang16", - "-G Ninja", - "-g" + "-G Ninja" ], "cmake.useCMakePresets": "auto", "editor.inlayHints.enabled": "offUnlessPressed", diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 056233c1c14..bcf233cffed 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.21.0 # x-release-please-version + VERSION 0.23.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/cpp/CMakePresets.json b/barretenberg/cpp/CMakePresets.json index 075068e6cd4..d967017743f 100644 --- a/barretenberg/cpp/CMakePresets.json +++ b/barretenberg/cpp/CMakePresets.json @@ -166,6 +166,16 @@ "LDFLAGS": "-fsanitize=memory" } }, + { + "name": "op-counting", + "displayName": "Release build with operation counts for benchmarks", + "description": "Build with op counting", + "inherits": "clang16", + "binaryDir": "build-op-counting", + "environment": { + "CXXFLAGS": "-DBB_USE_OP_COUNT" + } + }, { "name": "coverage", "displayName": "Build with coverage", @@ -300,6 +310,11 @@ "inherits": "default", "configurePreset": "clang16" }, + { + "name": "op-counting", + "inherits": "default", + "configurePreset": "op-counting" + }, { "name": "clang16-dbg", "inherits": "default", diff --git a/barretenberg/cpp/cmake/gtest.cmake b/barretenberg/cpp/cmake/gtest.cmake index c3551ea481a..79b81c75abe 100644 --- a/barretenberg/cpp/cmake/gtest.cmake +++ b/barretenberg/cpp/cmake/gtest.cmake @@ -1,17 +1,16 @@ include(GoogleTest) include(FetchContent) +set(BUILD_GMOCK ON CACHE INTERNAL BOOL "Build with gMock enabled") +set(INSTALL_GTEST OFF CACHE BOOL "gTest installation disabled") + FetchContent_Declare( GTest GIT_REPOSITORY https://github.com/google/googletest.git - # Version 1.12.1 is not compatible with WASI-SDK 12 - GIT_TAG release-1.10.0 + GIT_TAG v1.13.0 #v1.14.0 does not compile with gcc (compiler bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329) FIND_PACKAGE_ARGS ) -set(BUILD_GMOCK OFF CACHE BOOL "Build with gMock disabled") -set(INSTALL_GTEST OFF CACHE BOOL "gTest installation disabled") - FetchContent_MakeAvailable(GTest) if (NOT GTest_FOUND) @@ -42,8 +41,6 @@ if (NOT GTest_FOUND) gtest_disable_pthreads gtest_force_shared_crt gtest_hide_internal_symbols ) - add_library(GTest::gtest ALIAS gtest) - add_library(GTest::gtest_main ALIAS gtest_main) endif() enable_testing() diff --git a/barretenberg/cpp/cmake/module.cmake b/barretenberg/cpp/cmake/module.cmake index d394c024b9f..71fa5cd7dbe 100644 --- a/barretenberg/cpp/cmake/module.cmake +++ b/barretenberg/cpp/cmake/module.cmake @@ -77,6 +77,8 @@ function(barretenberg_module MODULE_NAME) ${MODULE_NAME}_test_objects PRIVATE GTest::gtest + GTest::gtest_main + GTest::gmock_main ${TBB_IMPORTED_TARGETS} ) @@ -118,6 +120,7 @@ function(barretenberg_module MODULE_NAME) ${ARGN} GTest::gtest GTest::gtest_main + GTest::gmock_main ${TBB_IMPORTED_TARGETS} ) diff --git a/barretenberg/cpp/scripts/bb-tests.sh b/barretenberg/cpp/scripts/bb-tests.sh index a4ba5b39417..0c0d27ed922 100755 --- a/barretenberg/cpp/scripts/bb-tests.sh +++ b/barretenberg/cpp/scripts/bb-tests.sh @@ -11,6 +11,7 @@ IMAGE_URI=$(calculate_image_uri $REPOSITORY) retry docker pull $IMAGE_URI TESTS=( + client_ivc_tests commitment_schemes_tests crypto_aes128_tests crypto_blake2s_tests diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 0ca963d4f87..3c996c513dc 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -49,6 +49,7 @@ else() endif() add_subdirectory(barretenberg/bb) +add_subdirectory(barretenberg/client_ivc) add_subdirectory(barretenberg/commitment_schemes) add_subdirectory(barretenberg/common) add_subdirectory(barretenberg/crypto) @@ -137,7 +138,8 @@ set(BARRETENBERG_TARGET_OBJECTS $ $ $ - $) + $ + $) add_library( barretenberg diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index b49d6f95908..fa91f8f3667 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -1,5 +1,9 @@ +#include "barretenberg/bb/file_io.hpp" +#include "barretenberg/common/serialize.hpp" #include "barretenberg/dsl/types.hpp" +#include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_execution.hpp" #include "config.hpp" #include "get_bn254_crs.hpp" #include "get_bytecode.hpp" @@ -12,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -506,6 +511,7 @@ int main(int argc, char* argv[]) if (command == "prove_and_verify_goblin") { return proveAndVerifyGoblin(bytecode_path, witness_path) ? 0 : 1; } + if (command == "prove") { std::string output_path = get_option(args, "-o", "./proofs/proof"); prove(bytecode_path, witness_path, output_path); @@ -528,6 +534,23 @@ int main(int argc, char* argv[]) } else if (command == "vk_as_fields") { std::string output_path = get_option(args, "-o", vk_path + "_fields.json"); vk_as_fields(vk_path, output_path); + } else if (command == "avm_prove") { + std::string avm_bytecode_path = get_option(args, "-b", "./target/avm_bytecode.bin"); + std::string output_path = get_option(args, "-o", "./proofs/avm_proof"); + std::vector call_data_bytes{}; + + if (flag_present(args, "-d")) { + auto const call_data_path = get_option(args, "-d", "./target/call_data.bin"); + call_data_bytes = read_file(call_data_path); + } + + srs::init_crs_factory("../srs_db/ignition"); + + std::vector const call_data = many_from_buffer(call_data_bytes); + auto const avm_bytecode = read_file(avm_bytecode_path); + auto const proof = avm_trace::Execution::run_and_prove(avm_bytecode, call_data); + std::vector const proof_bytes = to_buffer(proof); + write_file(output_path, proof_bytes); } else { std::cerr << "Unknown command: " << command << "\n"; return 1; diff --git a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt index 285f2bb5937..ae6fa95da27 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt @@ -1,10 +1,11 @@ +add_subdirectory(basics_bench) add_subdirectory(decrypt_bench) +add_subdirectory(goblin_bench) add_subdirectory(ipa_bench) +add_subdirectory(ivc_bench) add_subdirectory(pippenger_bench) add_subdirectory(plonk_bench) -add_subdirectory(ultra_bench) -add_subdirectory(goblin_bench) -add_subdirectory(basics_bench) +add_subdirectory(protogalaxy_bench) add_subdirectory(relations_bench) -add_subdirectory(widgets_bench) -add_subdirectory(protogalaxy_bench) \ No newline at end of file +add_subdirectory(ultra_bench) +add_subdirectory(widgets_bench) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/benchmark/basics_bench/basics.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/basics_bench/basics.bench.cpp index c3bf090f2cf..03614693396 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/basics_bench/basics.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/basics_bench/basics.bench.cpp @@ -20,6 +20,7 @@ * sequential_copy: 3.3 * */ +#include "barretenberg/common/op_count.hpp" #include "barretenberg/common/thread.hpp" #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp index 9c8fd4e51b7..8667c739dec 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp @@ -2,6 +2,7 @@ #include #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -48,7 +49,7 @@ class GoblinBench : public benchmark::Fixture { // Construct and accumulate the mock kernel circuit // Note: in first round, kernel_accum is empty since there is no previous kernel to recursively verify GoblinUltraCircuitBuilder circuit_builder{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(circuit_builder, function_accum, kernel_accum); + GoblinMockCircuits::construct_mock_recursion_kernel_circuit(circuit_builder, function_accum, kernel_accum); kernel_accum = goblin.accumulate(circuit_builder); } } @@ -67,6 +68,7 @@ BENCHMARK_DEFINE_F(GoblinBench, GoblinFull)(benchmark::State& state) GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); for (auto _ : state) { + BB_REPORT_OP_COUNT_IN_BENCH(state); // Perform a specified number of iterations of function/kernel accumulation perform_goblin_accumulation_rounds(state, goblin); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp index af594ba44e6..4f1719c141c 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ipa_bench/ipa.bench.cpp @@ -16,8 +16,8 @@ std::shared_ptr> crs_factory( auto ck = std::make_shared>(1 << MAX_POLYNOMIAL_DEGREE_LOG2, crs_factory); auto vk = std::make_shared>(1 << MAX_POLYNOMIAL_DEGREE_LOG2, crs_factory); -std::vector> prover_transcripts(MAX_POLYNOMIAL_DEGREE_LOG2 - - MIN_POLYNOMIAL_DEGREE_LOG2 + 1); +std::vector> prover_transcripts(MAX_POLYNOMIAL_DEGREE_LOG2 - + MIN_POLYNOMIAL_DEGREE_LOG2 + 1); std::vector> opening_claims(MAX_POLYNOMIAL_DEGREE_LOG2 - MIN_POLYNOMIAL_DEGREE_LOG2 + 1); void ipa_open(State& state) noexcept @@ -36,7 +36,7 @@ void ipa_open(State& state) noexcept const OpeningPair opening_pair = { x, eval }; const OpeningClaim opening_claim{ opening_pair, ck->commit(poly) }; // initialize empty prover transcript - auto prover_transcript = std::make_shared(); + auto prover_transcript = std::make_shared(); state.ResumeTiming(); // Compute proof IPA::compute_opening_proof(ck, opening_pair, poly, prover_transcript); @@ -53,7 +53,7 @@ void ipa_verify(State& state) noexcept auto prover_transcript = prover_transcripts[static_cast(state.range(0)) - MIN_POLYNOMIAL_DEGREE_LOG2]; auto opening_claim = opening_claims[static_cast(state.range(0)) - MIN_POLYNOMIAL_DEGREE_LOG2]; // initialize verifier transcript from proof data - auto verifier_transcript = std::make_shared(prover_transcript->proof_data); + auto verifier_transcript = std::make_shared(prover_transcript->proof_data); state.ResumeTiming(); auto result = IPA::verify(vk, opening_claim, verifier_transcript); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt new file mode 100644 index 00000000000..3f0c9245850 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(ivc_bench client_ivc stdlib_recursion stdlib_sha256 stdlib_merkle_tree stdlib_primitives) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp new file mode 100644 index 00000000000..2e1cacf27a1 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/benchmark/ivc_bench/ivc.bench.cpp @@ -0,0 +1,191 @@ + +#include + +#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/client_ivc/client_ivc.hpp" +#include "barretenberg/common/op_count_google_bench.hpp" +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +using namespace benchmark; +using namespace bb; + +namespace { + +/** + * @brief Benchmark suite for the aztec client PG-Goblin IVC scheme + * + */ +class IvcBench : public benchmark::Fixture { + public: + using Builder = GoblinUltraCircuitBuilder; + + // Number of function circuits to accumulate(based on Zacs target numbers) + static constexpr size_t NUM_ITERATIONS_MEDIUM_COMPLEXITY = 6; + + void SetUp([[maybe_unused]] const ::benchmark::State& state) override + { + bb::srs::init_crs_factory("../srs_db/ignition"); + bb::srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + /** + * @brief Perform a specified number of function circuit accumulation rounds + * @details Each round "accumulates" a mock function circuit and a mock kernel circuit. Each round thus consists + of + * the generation of two circuits, two folding proofs and two Merge proofs. To match the sizes called out in the + * spec + * (https://github.com/AztecProtocol/aztec-packages/blob/master/yellow-paper/docs/cryptography/performance-targets.md) + * we set the size of the function circuit to be 2^17. The first one should be 2^19 but we can't currently + support + * folding circuits of unequal size. + * + */ + static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) + { + static_cast(state); + static_cast(ivc); + // Initialize IVC with function circuit + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + ivc.initialize(function_circuit); + auto kernel_verifier_accum = ivc.get_verifier_accumulator(); + + // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) + Builder kernel_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(kernel_circuit); + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + auto kernel_verifier_inst = ivc.get_verifier_instance(); + + auto NUM_CIRCUITS = static_cast(state.range(0)); + // Subtract one to account for the "initialization" round above + NUM_CIRCUITS -= 1; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + Builder function_circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + auto function_fold_proof = ivc.accumulate(function_circuit); + auto fnct_verifier_inst = ivc.get_verifier_instance(); + + // Accumulate kernel circuit + Builder kernel_circuit{ ivc.goblin.op_queue }; + kernel_verifier_accum = GoblinMockCircuits::construct_mock_folding_kernel(kernel_circuit, + kernel_fold_proof, + function_fold_proof, + kernel_verifier_inst, + fnct_verifier_inst, + kernel_verifier_accum); + + kernel_fold_proof = ivc.accumulate(kernel_circuit); + kernel_verifier_inst = ivc.get_verifier_instance(); + } + } +}; + +/**ch + * @brief Benchmark the prover work for the full PG-Goblin IVC protocol + * + */ +BENCHMARK_DEFINE_F(IvcBench, Full)(benchmark::State& state) +{ + ClientIVC ivc; + + for (auto _ : state) { + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct IVC scheme proof (fold, decider, merge, eccvm, translator) + ivc.prove(); + } +} + +/** + * @brief Benchmark only the accumulation rounds + * + */ +BENCHMARK_DEFINE_F(IvcBench, Accumulate)(benchmark::State& state) +{ + ClientIVC ivc; + + // Perform a specified number of iterations of function/kernel accumulation + for (auto _ : state) { + perform_ivc_accumulation_rounds(state, ivc); + } +} + +/** + * @brief Benchmark only the Decider component + * + */ +BENCHMARK_DEFINE_F(IvcBench, Decide)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct eccvm proof, measure only translator proof construction + for (auto _ : state) { + ivc.decider_prove(); + } +} + +/** + * @brief Benchmark only the ECCVM component + * + */ +BENCHMARK_DEFINE_F(IvcBench, ECCVM)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct and measure eccvm only + for (auto _ : state) { + ivc.goblin.prove_eccvm(); + } +} + +/** + * @brief Benchmark only the Translator component + * + */ +BENCHMARK_DEFINE_F(IvcBench, Translator)(benchmark::State& state) +{ + ClientIVC ivc; + + BB_REPORT_OP_COUNT_IN_BENCH(state); + // Perform a specified number of iterations of function/kernel accumulation + perform_ivc_accumulation_rounds(state, ivc); + + // Construct eccvm proof, measure only translator proof construction + ivc.goblin.prove_eccvm(); + for (auto _ : state) { + ivc.goblin.prove_translator(); + } +} + +#define ARGS \ + Arg(IvcBench::NUM_ITERATIONS_MEDIUM_COMPLEXITY) \ + ->Arg(1 << 0) \ + ->Arg(1 << 1) \ + ->Arg(1 << 2) \ + ->Arg(1 << 3) \ + ->Arg(1 << 4) \ + ->Arg(1 << 5) \ + ->Arg(1 << 6) + +BENCHMARK_REGISTER_F(IvcBench, Full)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Accumulate)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Decide)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, ECCVM)->Unit(benchmark::kMillisecond)->ARGS; +BENCHMARK_REGISTER_F(IvcBench, Translator)->Unit(benchmark::kMillisecond)->ARGS; + +} // namespace + +BENCHMARK_MAIN(); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp index 156587d5133..591acab34e2 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp @@ -24,7 +24,7 @@ void fold_one(State& state) noexcept const auto construct_instance = [&]() { Builder builder; bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); - return composer.create_instance(builder); + return composer.create_prover_instance(builder); }; std::shared_ptr instance_1 = construct_instance(); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp index da9c1f2f108..8ab0220e838 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp @@ -54,7 +54,7 @@ inline UltraProver get_prover(UltraComposer& composer, { UltraComposer::CircuitBuilder builder; test_circuit_function(builder, num_iterations); - std::shared_ptr instance = composer.create_instance(builder); + std::shared_ptr instance = composer.create_prover_instance(builder); return composer.create_prover(instance); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp index e91343143a8..088308eb7db 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp @@ -1,6 +1,7 @@ #include #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/ultra_honk/ultra_composer.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" @@ -27,15 +28,20 @@ enum { * @param prover - The ultrahonk prover. * @param index - The pass to measure. **/ -BBERG_PROFILE static void test_round_inner(State& state, UltraProver& prover, size_t index) noexcept +BB_PROFILE static void test_round_inner(State& state, UltraProver& prover, size_t index) noexcept { auto time_if_index = [&](size_t target_index, auto&& func) -> void { + BB_REPORT_OP_COUNT_IN_BENCH(state); if (index == target_index) { state.ResumeTiming(); } + func(); if (index == target_index) { state.PauseTiming(); + } else { + // We don't actually want to write to user-defined counters + BB_REPORT_OP_COUNT_BENCH_CANCEL(); } }; @@ -47,7 +53,7 @@ BBERG_PROFILE static void test_round_inner(State& state, UltraProver& prover, si time_if_index(RELATION_CHECK, [&] { prover.execute_relation_check_rounds(); }); time_if_index(ZEROMORPH, [&] { prover.execute_zeromorph_rounds(); }); } -BBERG_PROFILE static void test_round(State& state, size_t index) noexcept +BB_PROFILE static void test_round(State& state, size_t index) noexcept { bb::srs::init_crs_factory("../srs_db/ignition"); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp index 45e82fe144e..8fa44c08809 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp @@ -17,7 +17,7 @@ enum { SIXTH_BATCH_OPEN }; -BBERG_PROFILE static void plonk_round( +BB_PROFILE static void plonk_round( State& state, plonk::UltraProver& prover, size_t target_index, size_t index, auto&& func) noexcept { if (index == target_index) { @@ -37,7 +37,7 @@ BBERG_PROFILE static void plonk_round( * @param prover - The ultraplonk prover. * @param index - The pass to measure. **/ -BBERG_PROFILE static void test_round_inner(State& state, plonk::UltraProver& prover, size_t index) noexcept +BB_PROFILE static void test_round_inner(State& state, plonk::UltraProver& prover, size_t index) noexcept { plonk_round(state, prover, PREAMBLE, index, [&] { prover.execute_preamble_round(); }); plonk_round(state, prover, FIRST_WIRE_COMMITMENTS, index, [&] { prover.execute_first_round(); }); @@ -47,7 +47,7 @@ BBERG_PROFILE static void test_round_inner(State& state, plonk::UltraProver& pro plonk_round(state, prover, FIFTH_COMPUTE_QUOTIENT_EVALUTION, index, [&] { prover.execute_fifth_round(); }); plonk_round(state, prover, SIXTH_BATCH_OPEN, index, [&] { prover.execute_sixth_round(); }); } -BBERG_PROFILE static void test_round(State& state, size_t index) noexcept +BB_PROFILE static void test_round(State& state, size_t index) noexcept { bb::srs::init_crs_factory("../srs_db/ignition"); for (auto _ : state) { diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt new file mode 100644 index 00000000000..e4f75e5e984 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(client_ivc goblin) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp new file mode 100644 index 00000000000..2cae9315c09 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -0,0 +1,101 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" + +namespace bb { + +ClientIVC::ClientIVC() +{ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); +} + +/** + * @brief Initialize the IVC with a first circuit + * @details Initializes the accumulator and performs the initial goblin merge + * + * @param circuit + */ +void ClientIVC::initialize(ClientCircuit& circuit) +{ + goblin.merge(circuit); // Construct new merge proof + Composer composer; + prover_fold_output.accumulator = composer.create_prover_instance(circuit); +} + +/** + * @brief Accumulate a circuit into the IVC scheme + * @details Performs goblin merge, generates circuit instance, folds into accumulator and constructs a folding proof + * + * @param circuit Circuit to be accumulated/folded + * @return FoldProof + */ +ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) +{ + goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof + Composer composer; + prover_instance = composer.create_prover_instance(circuit); + auto folding_prover = composer.create_folding_prover({ prover_fold_output.accumulator, prover_instance }); + prover_fold_output = folding_prover.fold_instances(); + return prover_fold_output.folding_data; +} + +/** + * @brief Construct a proof for the IVC, which, if verified, fully establishes its correctness + * + * @return Proof + */ +ClientIVC::Proof ClientIVC::prove() +{ + return { prover_fold_output.folding_data, decider_prove(), goblin.prove() }; +} + +/** + * @brief Verify a full proof of the IVC + * + * @param proof + * @return bool + */ +bool ClientIVC::verify(Proof& proof, const std::vector& verifier_instances) +{ + // Goblin verification (merge, eccvm, translator) + bool goblin_verified = goblin.verify(proof.goblin_proof); + + // Decider verification + Composer composer; + auto folding_verifier = composer.create_folding_verifier({ verifier_instances[0], verifier_instances[1] }); + auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.fold_proof); + // NOTE: Use of member accumulator here will go away with removal of vkey from ProverInstance + auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); + bool decision = decider_verifier.verify_proof(proof.decider_proof); + return goblin_verified && decision; +} + +/** + * @brief Internal method for constructing a decider proof + * + * @return HonkProof + */ +HonkProof ClientIVC::decider_prove() const +{ + Composer composer; + auto decider_prover = composer.create_decider_prover(prover_fold_output.accumulator); + return decider_prover.construct_proof(); +} + +std::shared_ptr ClientIVC::get_verifier_instance() +{ + Composer composer; + composer.compute_commitment_key(prover_instance->instance_size); + auto verifier_instance = composer.create_verifier_instance(prover_instance); + return verifier_instance; +} + +ClientIVC::VerifierAccumulator ClientIVC::get_verifier_accumulator() +{ + Composer composer; + auto prover_accumulator = prover_fold_output.accumulator; + composer.compute_commitment_key(prover_accumulator->instance_size); + auto verifier_accumulator = composer.create_verifier_instance(prover_accumulator); + return verifier_accumulator; +} + +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp new file mode 100644 index 00000000000..15d24ddce85 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +namespace bb { + +/** + * @brief The IVC interface to be used by the aztec client for private function execution + * @details Combines Protogalaxy with Goblin to accumulate one circuit instance at a time with efficient EC group + * operations + * + */ +class ClientIVC { + + public: + using Flavor = GoblinUltraFlavor; + using FF = Flavor::FF; + using FoldProof = std::vector; + using ProverAccumulator = std::shared_ptr>; + using VerifierAccumulator = std::shared_ptr>; + using VerifierInstance = VerifierInstance_; + using ProverInstance = ProverInstance_; + using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra + + // A full proof for the IVC scheme + struct Proof { + FoldProof fold_proof; // final fold proof + HonkProof decider_proof; + Goblin::Proof goblin_proof; + }; + + private: + using ProverFoldOutput = FoldingResult; + using Composer = GoblinUltraComposer; + + public: + Goblin goblin; + ProverFoldOutput prover_fold_output; + ProverAccumulator prover_accumulator; + + // keep the instance or instances around if we're folding more of them so we can compute the verification key + std::shared_ptr prover_instance; + + ClientIVC(); + + void initialize(ClientCircuit& circuit); + + FoldProof accumulate(ClientCircuit& circuit); + + Proof prove(); + + bool verify(Proof& proof, const std::vector& verifier_instances); + + HonkProof decider_prove() const; + + VerifierAccumulator get_verifier_accumulator(); + std::shared_ptr get_verifier_instance(); +}; +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp new file mode 100644 index 00000000000..d767f1c7e56 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -0,0 +1,149 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +#include +using namespace bb; + +class ClientIVCTests : public ::testing::Test { + protected: + static void SetUpTestSuite() + { + srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + using Flavor = ClientIVC::Flavor; + using FF = typename Flavor::FF; + using Builder = ClientIVC::ClientCircuit; + using Composer = GoblinUltraComposer; + using ProverAccumulator = ClientIVC::ProverAccumulator; + using VerifierAccumulator = ClientIVC::VerifierAccumulator; + using VerifierInstance = std::shared_ptr; + using FoldProof = ClientIVC::FoldProof; + + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; + using RecursiveVerifierAccumulator = std::shared_ptr; + using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + + /** + * @brief Construct mock circuit with arithmetic gates and goblin ops + * @details Currently default sized to 2^16 to match kernel. (Note: op gates will bump size to next power of + 2) + * + */ + static Builder create_mock_circuit(ClientIVC& ivc, size_t num_gates = 1 << 15) + { + Builder circuit{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_arithmetic_circuit(circuit, num_gates); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit); + return circuit; + } + + /** + * @brief Construct mock kernel consisting of two recursive folding verifiers + * + * @param builder + * @param fctn_fold_proof + * @param kernel_fold_proof + */ + static VerifierAccumulator construct_mock_folding_kernel(Builder& builder, + FoldProof& fold_proof_1, + FoldProof& fold_proof_2, + VerifierInstance& verifier_inst_1, + VerifierInstance& verifier_inst_2, + VerifierAccumulator& prev_kernel_accum) + { + + FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { verifier_inst_1->verification_key } }; + auto fctn_verifier_accum = verifier_1.verify_folding_proof(fold_proof_1); + auto native_acc = std::make_shared(fctn_verifier_accum->get_value()); + FoldingRecursiveVerifier verifier_2{ &builder, native_acc, { verifier_inst_2->verification_key } }; + auto kernel_verifier_accum = verifier_2.verify_folding_proof(fold_proof_2); + return std::make_shared(kernel_verifier_accum->get_value()); + } + + /** + * @brief Construct mock kernel consisting of two recursive folding verifiers + * + * @param builder + * @param fctn_fold_proof + * @param kernel_fold_proof + */ + + /** + * @brief Perform native fold verification and run decider prover/verifier + * + */ + // static VerifierAccumulator native_folding(const ProverAccumulator& prover_accumulator, + // const std::vector>& + // verifier_instances, const FoldProof& fold_proof) + // { + // // Verify fold proof + // Composer composer; + // auto folding_verifier = composer.create_folding_verifier(verifier_instances); + // auto verifier_accumulator = folding_verifier.verify_folding_proof(fold_proof); + + // // Run decider + // auto decider_prover = composer.create_decider_prover(prover_accumulator); + // auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); + // auto decider_proof = decider_prover.construct_proof(); + // bool decision = decider_verifier.verify_proof(decider_proof); + // EXPECT_TRUE(decision); + // } +}; + +/** + * @brief A full Goblin test using PG that mimicks the basic aztec client architecture + * + */ +TEST_F(ClientIVCTests, Full) +{ + ClientIVC ivc; + + // Initialize IVC with function circuit + Builder function_circuit_1 = create_mock_circuit(ivc); + ivc.initialize(function_circuit_1); + VerifierAccumulator kernel_verifier_accum = + ivc.get_verifier_accumulator(); // fake accumulator, just a function circuit for the first round + + Builder kernel_circuit = create_mock_circuit(ivc); + FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); + auto kernel_verifier_inst = ivc.get_verifier_instance(); + size_t NUM_CIRCUITS = 2; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + // Accumulate function circuit + Builder function_circuit = create_mock_circuit(ivc); + FoldProof function_fold_proof = ivc.accumulate(function_circuit); + auto fnct_verifier_inst = ivc.get_verifier_instance(); + + // Accumulate kernel circuit + Builder kernel_circuit{ ivc.goblin.op_queue }; + + kernel_verifier_accum = construct_mock_folding_kernel(kernel_circuit, + kernel_fold_proof, + function_fold_proof, + kernel_verifier_inst, + fnct_verifier_inst, + kernel_verifier_accum); + + kernel_fold_proof = ivc.accumulate(kernel_circuit); + kernel_verifier_inst = ivc.get_verifier_instance(); + } + + // // Constuct four proofs: merge, eccvm, translator, decider, last folding proof + auto proof = ivc.prove(); + + // // Verify all four proofs + auto verifier_instances = std::vector{ kernel_verifier_accum, kernel_verifier_inst }; + auto res = ivc.verify(proof, verifier_instances); + + EXPECT_TRUE(res); +}; \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp new file mode 100644 index 00000000000..a857bd913f2 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -0,0 +1,59 @@ +#include "barretenberg/client_ivc/client_ivc.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include + +using namespace bb; + +/** + * @brief For benchmarking, we want to be sure that our mocking functions create circuits of a known size. We control + * this, to the degree that matters for proof construction time, using these "pinning tests" that fix values. + * + */ +class MockKernelTest : public ::testing::Test { + protected: + static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } +}; + +TEST_F(MockKernelTest, PinFoldingKernelSizes) +{ + ClientIVC ivc; + + // Accumulate three circuits to generate two folding proofs for input to folding kernel + GoblinUltraCircuitBuilder circuit_1{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_1); + ivc.initialize(circuit_1); + auto verifier_acc = ivc.get_verifier_accumulator(); + + GoblinUltraCircuitBuilder circuit_2{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_2); + auto fold_proof_1 = ivc.accumulate(circuit_2); + auto verifier_inst_1 = ivc.get_verifier_instance(); + + GoblinUltraCircuitBuilder circuit_3{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_3); + auto fold_proof_2 = ivc.accumulate(circuit_3); + auto verifier_inst_2 = ivc.get_verifier_instance(); + + // Construct kernel circuit + GoblinUltraCircuitBuilder kernel_circuit{ ivc.goblin.op_queue }; + auto new_acc = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, fold_proof_1, fold_proof_2, verifier_inst_1, verifier_inst_2, verifier_acc); + + auto fold_proof_3 = ivc.accumulate(kernel_circuit); + auto verifier_inst_3 = ivc.get_verifier_instance(); + EXPECT_EQ(ivc.prover_instance->log_instance_size, 17); + + GoblinUltraCircuitBuilder circuit_4{ ivc.goblin.op_queue }; + GoblinMockCircuits::construct_mock_function_circuit(circuit_4); + auto fold_proof_4 = ivc.accumulate(circuit_4); + auto verifier_inst_4 = ivc.get_verifier_instance(); + + GoblinUltraCircuitBuilder new_kernel_circuit = GoblinUltraCircuitBuilder{ ivc.goblin.op_queue }; + new_acc = GoblinMockCircuits::construct_mock_folding_kernel( + new_kernel_circuit, fold_proof_3, fold_proof_4, verifier_inst_3, verifier_inst_4, new_acc); + GoblinUltraComposer composer; + auto instance = composer.create_prover_instance(new_kernel_circuit); + EXPECT_EQ(instance->proving_key->log_circuit_size, 17); +} \ 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 6edf56c0b4b..94fbd5c43c7 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.hpp @@ -149,7 +149,7 @@ template class GeminiVerifier_ { } // compute vector of powers of random evaluation point r - const Fr r = transcript->get_challenge("Gemini:r"); + const Fr r = transcript->template get_challenge("Gemini:r"); std::vector r_squares = gemini::squares_of_r(r, num_variables); // Get evaluations a_i, i = 0,...,m-1 from transcript 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 0574dcfa115..7e378bba250 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/gemini/gemini.test.cpp @@ -25,7 +25,7 @@ template class GeminiTest : public CommitmentTest { std::vector multilinear_commitments, std::vector multilinear_commitments_to_be_shifted) { - auto prover_transcript = BaseTranscript::prover_init_empty(); + auto prover_transcript = NativeTranscript::prover_init_empty(); const Fr rho = Fr::random_element(); @@ -65,7 +65,7 @@ template class GeminiTest : public CommitmentTest { prover_transcript->send_to_verifier(label, commitment); } - const Fr r_challenge = prover_transcript->get_challenge("Gemini:r"); + const Fr r_challenge = prover_transcript->get_challenge("Gemini:r"); auto prover_output = GeminiProver::compute_fold_polynomial_evaluations( multilinear_evaluation_point, std::move(gemini_polynomials), r_challenge); @@ -79,7 +79,7 @@ template class GeminiTest : public CommitmentTest { // Check that the Fold polynomials have been evaluated correctly in the prover this->verify_batch_opening_pair(prover_output.opening_pairs, prover_output.witnesses); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // Compute: // - Single opening pair: {r, \hat{a}_0} diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index ccac4dbdc2f..b179a6dee7e 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -36,12 +36,12 @@ template class IPA { static void compute_opening_proof(const std::shared_ptr& ck, const OpeningPair& opening_pair, const Polynomial& polynomial, - const std::shared_ptr& transcript) + const std::shared_ptr& transcript) { ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); auto poly_degree = static_cast(polynomial.size()); - transcript->send_to_verifier("IPA:poly_degree", static_cast(poly_degree)); - const Fr generator_challenge = transcript->get_challenge("IPA:generator_challenge"); + transcript->send_to_verifier("IPA:poly_degree", static_cast(poly_degree)); + const Fr generator_challenge = transcript->template get_challenge("IPA:generator_challenge"); auto aux_generator = Commitment::one() * generator_challenge; // Checks poly_degree is greater than zero and a power of two // In the future, we might want to consider if non-powers of two are needed @@ -138,7 +138,7 @@ template class IPA { transcript->send_to_verifier("IPA:R_" + index, Commitment(R_elements[i])); // Generate the round challenge. - const Fr round_challenge = transcript->get_challenge("IPA:round_challenge_" + index); + const Fr round_challenge = transcript->get_challenge("IPA:round_challenge_" + index); const Fr round_challenge_inv = round_challenge.invert(); auto G_lo = GroupElement::batch_mul_with_endomorphism( @@ -183,10 +183,12 @@ template class IPA { */ static bool verify(const std::shared_ptr& vk, const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + const std::shared_ptr& transcript) { - auto poly_degree = static_cast(transcript->template receive_from_prover("IPA:poly_degree")); - const Fr generator_challenge = transcript->get_challenge("IPA:generator_challenge"); + auto poly_degree = static_cast(transcript->template receive_from_prover( + "IPA:poly_degree")); // note this is base field because this is a uint32_t, which should map to a bb::fr, + // not a grumpkin::fr, which is a BaseField element for Grumpkin + const Fr generator_challenge = transcript->template get_challenge("IPA:generator_challenge"); auto aux_generator = Commitment::one() * generator_challenge; auto log_poly_degree = static_cast(numeric::get_msb(poly_degree)); @@ -204,7 +206,7 @@ template class IPA { std::string index = std::to_string(i); auto element_L = transcript->template receive_from_prover("IPA:L_" + index); auto element_R = transcript->template receive_from_prover("IPA:R_" + index); - round_challenges[i] = transcript->get_challenge("IPA:round_challenge_" + index); + round_challenges[i] = transcript->template get_challenge("IPA:round_challenge_" + index); round_challenges_inv[i] = round_challenges[i].invert(); msm_elements[2 * i] = element_L; 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 b1d61d63df4..719be120fda 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -72,11 +72,11 @@ TEST_F(IPATest, Open) const OpeningClaim opening_claim{ opening_pair, commitment }; // initialize empty prover transcript - auto prover_transcript = std::make_shared(); + auto prover_transcript = std::make_shared(); IPA::compute_opening_proof(this->ck(), opening_pair, poly, prover_transcript); // initialize verifier transcript from proof data - auto verifier_transcript = std::make_shared(prover_transcript->proof_data); + auto verifier_transcript = std::make_shared(prover_transcript->proof_data); auto result = IPA::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_TRUE(result); @@ -131,7 +131,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) batched_commitment_unshifted = commitment1 * rhos[0] + commitment2 * rhos[1]; batched_commitment_to_be_shifted = commitment2 * rhos[2]; - auto prover_transcript = BaseTranscript::prover_init_empty(); + auto prover_transcript = NativeTranscript::prover_init_empty(); auto gemini_polynomials = GeminiProver::compute_gemini_polynomials( mle_opening_point, std::move(batched_unshifted), std::move(batched_to_be_shifted)); @@ -142,7 +142,7 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) prover_transcript->send_to_verifier(label, commitment); } - const Fr r_challenge = prover_transcript->get_challenge("Gemini:r"); + const Fr r_challenge = prover_transcript->template get_challenge("Gemini:r"); const auto [gemini_opening_pairs, gemini_witnesses] = GeminiProver::compute_fold_polynomial_evaluations( mle_opening_point, std::move(gemini_polynomials), r_challenge); @@ -153,18 +153,18 @@ TEST_F(IPATest, GeminiShplonkIPAWithShift) prover_transcript->send_to_verifier(label, evaluation); } - const Fr nu_challenge = prover_transcript->get_challenge("Shplonk:nu"); + const Fr nu_challenge = prover_transcript->template get_challenge("Shplonk:nu"); auto batched_quotient_Q = ShplonkProver::compute_batched_quotient(gemini_opening_pairs, gemini_witnesses, nu_challenge); prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q)); - const Fr z_challenge = prover_transcript->get_challenge("Shplonk:z"); + const Fr z_challenge = prover_transcript->template get_challenge("Shplonk:z"); const auto [shplonk_opening_pair, shplonk_witness] = ShplonkProver::compute_partially_evaluated_batched_quotient( gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); IPA::compute_opening_proof(this->ck(), shplonk_opening_pair, shplonk_witness, prover_transcript); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); auto gemini_verifier_claim = GeminiVerifier::reduce_verification(mle_opening_point, batched_evaluation, diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp index 1e4a0f1b18e..8a322620000 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp @@ -31,7 +31,7 @@ template class KZG { static void compute_opening_proof(std::shared_ptr ck, const OpeningPair& opening_pair, const Polynomial& polynomial, - const std::shared_ptr& prover_trancript) + const std::shared_ptr& prover_trancript) { Polynomial quotient = polynomial; quotient[0] -= opening_pair.evaluation; @@ -55,7 +55,7 @@ template class KZG { */ static bool verify(const std::shared_ptr& vk, const OpeningClaim& claim, - const std::shared_ptr& verifier_transcript) + const std::shared_ptr& verifier_transcript) { auto quotient_commitment = verifier_transcript->template receive_from_prover("KZG:W"); auto lhs = claim.commitment - (GroupElement::one() * claim.opening_pair.evaluation) + @@ -82,7 +82,7 @@ template class KZG { GroupElement P_0; if constexpr (Curve::is_stdlib_type) { - auto builder = verifier_transcript->builder; + auto builder = quotient_commitment.get_context(); auto one = Fr(builder, 1); std::vector commitments = { claim.commitment, quotient_commitment, 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 9e45ffff90a..4ec38c45561 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.test.cpp @@ -39,11 +39,11 @@ TYPED_TEST(KZGTest, single) auto opening_pair = OpeningPair{ challenge, evaluation }; auto opening_claim = OpeningClaim{ opening_pair, commitment }; - auto prover_transcript = BaseTranscript::prover_init_empty(); + auto prover_transcript = NativeTranscript::prover_init_empty(); KZG::compute_opening_proof(this->ck(), opening_pair, witness, prover_transcript); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); bool verified = KZG::verify(this->vk(), opening_claim, verifier_transcript); EXPECT_EQ(verified, true); @@ -109,7 +109,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) batched_commitment_unshifted = commitment1 * rhos[0] + commitment2 * rhos[1]; batched_commitment_to_be_shifted = commitment2 * rhos[2]; - auto prover_transcript = BaseTranscript::prover_init_empty(); + auto prover_transcript = NativeTranscript::prover_init_empty(); // Run the full prover PCS protocol: @@ -125,7 +125,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) prover_transcript->send_to_verifier(label, commitment); } - const Fr r_challenge = prover_transcript->get_challenge("Gemini:r"); + const Fr r_challenge = prover_transcript->template get_challenge("Gemini:r"); const auto [gemini_opening_pairs, gemini_witnesses] = GeminiProver::compute_fold_polynomial_evaluations( mle_opening_point, std::move(gemini_polynomials), r_challenge); @@ -139,12 +139,12 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // Shplonk prover output: // - opening pair: (z_challenge, 0) // - witness: polynomial Q - Q_z - const Fr nu_challenge = prover_transcript->get_challenge("Shplonk:nu"); + const Fr nu_challenge = prover_transcript->template get_challenge("Shplonk:nu"); auto batched_quotient_Q = ShplonkProver::compute_batched_quotient(gemini_opening_pairs, gemini_witnesses, nu_challenge); prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q)); - const Fr z_challenge = prover_transcript->get_challenge("Shplonk:z"); + const Fr z_challenge = prover_transcript->template get_challenge("Shplonk:z"); const auto [shplonk_opening_pair, shplonk_witness] = ShplonkProver::compute_partially_evaluated_batched_quotient( gemini_opening_pairs, gemini_witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); @@ -154,7 +154,7 @@ TYPED_TEST(KZGTest, GeminiShplonkKzgWithShift) // Run the full verifier PCS protocol with genuine opening claims (genuine commitment, genuine evaluation) - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // 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 diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp index a73ffa37a8f..fb08f81d889 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.hpp @@ -168,11 +168,11 @@ template class ShplonkVerifier_ { const size_t num_claims = claims.size(); - const Fr nu = transcript->get_challenge("Shplonk:nu"); + const Fr nu = transcript->template get_challenge("Shplonk:nu"); auto Q_commitment = transcript->template receive_from_prover("Shplonk:Q"); - const Fr z_challenge = transcript->get_challenge("Shplonk:z"); + const Fr z_challenge = transcript->template get_challenge("Shplonk:z"); // [G] = [Q] - ∑ⱼ ρʲ / ( r − xⱼ )⋅[fⱼ] + G₀⋅[1] // = [Q] - [∑ⱼ ρʲ ⋅ ( fⱼ(X) − vⱼ) / ( r − xⱼ )] diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp index ee5168b2253..35976616526 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/shplonk/shplonk.test.cpp @@ -28,7 +28,7 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) const size_t n = 16; - auto prover_transcript = BaseTranscript::prover_init_empty(); + auto prover_transcript = NativeTranscript::prover_init_empty(); // Generate two random (unrelated) polynomials of two different sizes, as well as their evaluations at a (single but // different) random point and their commitments. @@ -47,11 +47,11 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) std::vector polynomials = { poly1.share(), poly2.share() }; // Execute the shplonk prover functionality - const Fr nu_challenge = prover_transcript->get_challenge("Shplonk:nu"); + const Fr nu_challenge = prover_transcript->template get_challenge("Shplonk:nu"); auto batched_quotient_Q = ShplonkProver::compute_batched_quotient(opening_pairs, polynomials, nu_challenge); prover_transcript->send_to_verifier("Shplonk:Q", this->ck()->commit(batched_quotient_Q)); - const Fr z_challenge = prover_transcript->get_challenge("Shplonk:z"); + const Fr z_challenge = prover_transcript->template get_challenge("Shplonk:z"); const auto [prover_opening_pair, shplonk_prover_witness] = ShplonkProver::compute_partially_evaluated_batched_quotient( opening_pairs, polynomials, std::move(batched_quotient_Q), nu_challenge, z_challenge); @@ -64,7 +64,7 @@ TYPED_TEST(ShplonkTest, ShplonkSimple) opening_claims.emplace_back(OpeningClaim{ opening_pairs[0], commitment1 }); opening_claims.emplace_back(OpeningClaim{ opening_pairs[1], commitment2 }); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // Execute the shplonk verifier functionality const auto verifier_claim = ShplonkVerifier::reduce_verification(this->vk(), opening_claims, verifier_transcript); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index ce1e8c6fdd1..8441b8dd21d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -322,13 +322,13 @@ template class ZeroMorphProver_ { const std::vector& g_shift_evaluations, const std::vector& multilinear_challenge, const std::shared_ptr>& commitment_key, - const std::shared_ptr& transcript, + const std::shared_ptr& transcript, const std::vector& concatenated_polynomials = {}, const std::vector& concatenated_evaluations = {}, const std::vector>& concatenation_groups = {}) { // Generate batching challenge \rho and powers 1,...,\rho^{m-1} - const FF rho = transcript->get_challenge("rho"); + const FF rho = transcript->template get_challenge("rho"); // Extract multilinear challenge u and claimed multilinear evaluations from Sumcheck output std::span u_challenge = multilinear_challenge; @@ -397,7 +397,7 @@ template class ZeroMorphProver_ { } // Get challenge y - FF y_challenge = transcript->get_challenge("ZM:y"); + FF y_challenge = transcript->template get_challenge("ZM:y"); // Compute the batched, lifted-degree quotient \hat{q} auto batched_quotient = compute_batched_lifted_degree_quotient(quotients, y_challenge, N); @@ -407,7 +407,7 @@ template class ZeroMorphProver_ { transcript->send_to_verifier("ZM:C_q", q_commitment); // Get challenges x and z - auto [x_challenge, z_challenge] = challenges_to_field_elements(transcript->get_challenges("ZM:x", "ZM:z")); + auto [x_challenge, z_challenge] = transcript->template get_challenges("ZM:x", "ZM:z"); // Compute degree check polynomial \zeta partially evaluated at x auto zeta_x = @@ -644,7 +644,7 @@ template class ZeroMorphVerifier_ { const std::vector& concatenated_evaluations = {}) { size_t log_N = multivariate_challenge.size(); - FF rho = transcript->get_challenge("rho"); + FF rho = transcript->template get_challenge("rho"); // Construct batched evaluation v = sum_{i=0}^{m-1}\rho^i*f_i(u) + sum_{i=0}^{l-1}\rho^{m+i}*h_i(u) FF batched_evaluation = FF(0); @@ -670,13 +670,13 @@ template class ZeroMorphVerifier_ { } // Challenge y - FF y_challenge = transcript->get_challenge("ZM:y"); + FF y_challenge = transcript->template get_challenge("ZM:y"); // Receive commitment C_{q} auto C_q = transcript->template receive_from_prover("ZM:C_q"); // Challenges x, z - auto [x_challenge, z_challenge] = challenges_to_field_elements(transcript->get_challenges("ZM:x", "ZM:z")); + auto [x_challenge, z_challenge] = transcript->template get_challenges("ZM:x", "ZM:z"); // Compute commitment C_{\zeta_x} auto C_zeta_x = compute_C_zeta_x(C_q, C_q_k, y_challenge, x_challenge); diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp index b963ecb0511..084e003c0a4 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp @@ -74,8 +74,8 @@ template class ZeroMorphTest : public CommitmentTest { g_commitments.emplace_back(f_commitments[i]); } - // Initialize an empty BaseTranscript - auto prover_transcript = BaseTranscript::prover_init_empty(); + // Initialize an empty NativeTranscript + auto prover_transcript = NativeTranscript::prover_init_empty(); // Execute Prover protocol ZeroMorphProver::prove(f_polynomials, @@ -86,7 +86,7 @@ template class ZeroMorphTest : public CommitmentTest { this->commitment_key, prover_transcript); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // Execute Verifier protocol auto pairing_points = ZeroMorphVerifier::verify( @@ -220,8 +220,8 @@ template class ZeroMorphWithConcatenationTest : public CommitmentT concatenation_groups_commitments.emplace_back(concatenation_group_commitment); } - // Initialize an empty BaseTranscript - auto prover_transcript = BaseTranscript::prover_init_empty(); + // Initialize an empty NativeTranscript + auto prover_transcript = NativeTranscript::prover_init_empty(); // Execute Prover protocol ZeroMorphProver::prove(f_polynomials, // unshifted @@ -235,7 +235,7 @@ template class ZeroMorphWithConcatenationTest : public CommitmentT c_evaluations, to_vector_of_ref_vectors(concatenation_groups)); - auto verifier_transcript = BaseTranscript::verifier_init_empty(prover_transcript); + auto verifier_transcript = NativeTranscript::verifier_init_empty(prover_transcript); // Execute Verifier protocol auto pairing_points = ZeroMorphVerifier::verify(f_commitments, // unshifted diff --git a/barretenberg/cpp/src/barretenberg/common/compiler_hints.hpp b/barretenberg/cpp/src/barretenberg/common/compiler_hints.hpp index 1815816a3c4..9492475cc1c 100644 --- a/barretenberg/cpp/src/barretenberg/common/compiler_hints.hpp +++ b/barretenberg/cpp/src/barretenberg/common/compiler_hints.hpp @@ -1,16 +1,26 @@ #pragma once #ifdef _WIN32 -#define BBERG_INLINE __forceinline inline +#define BB_INLINE __forceinline inline #else -#define BBERG_INLINE __attribute__((always_inline)) inline +#define BB_INLINE __attribute__((always_inline)) inline #endif // TODO(AD): Other instrumentation? #ifdef XRAY -#define BBERG_PROFILE [[clang::xray_always_instrument]] [[clang::noinline]] -#define BBERG_NO_PROFILE [[clang::xray_never_instrument]] +#define BB_PROFILE [[clang::xray_always_instrument]] [[clang::noinline]] +#define BB_NO_PROFILE [[clang::xray_never_instrument]] #else -#define BBERG_PROFILE -#define BBERG_NO_PROFILE +#define BB_PROFILE +#define BB_NO_PROFILE +#endif + +// Optimization hints for clang - which outcome of an expression is expected for better +// branch-prediction optimization +#ifdef __clang__ +#define BB_LIKELY(x) __builtin_expect(!!(x), 1) +#define BB_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define BB_LIKELY(x) x +#define BB_UNLIKELY(x) x #endif \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/op_count.cpp b/barretenberg/cpp/src/barretenberg/common/op_count.cpp new file mode 100644 index 00000000000..c646c88d829 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/op_count.cpp @@ -0,0 +1,51 @@ + +#include +#ifdef BB_USE_OP_COUNT +#include "op_count.hpp" +#include +#include +#include + +namespace bb::detail { +void GlobalOpCountContainer::add_entry(const char* key, std::size_t* count) +{ + std::unique_lock lock(mutex); + std::stringstream ss; + ss << std::this_thread::get_id(); + counts.push_back({ key, ss.str(), count }); +} + +void GlobalOpCountContainer::print() const +{ + std::cout << "print_op_counts() START" << std::endl; + for (const Entry& entry : counts) { + if (*entry.count > 0) { + std::cout << entry.key << "\t" << *entry.count << "\t[thread=" << entry.thread_id << "]" << std::endl; + } + } + std::cout << "print_op_counts() END" << std::endl; +} + +std::map GlobalOpCountContainer::get_aggregate_counts() const +{ + std::map aggregate_counts; + for (const Entry& entry : counts) { + if (*entry.count > 0) { + aggregate_counts[entry.key] += *entry.count; + } + } + return aggregate_counts; +} + +void GlobalOpCountContainer::clear() +{ + std::unique_lock lock(mutex); + for (Entry& entry : counts) { + *entry.count = 0; + } +} + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +GlobalOpCountContainer GLOBAL_OP_COUNTS; +} // namespace bb::detail +#endif diff --git a/barretenberg/cpp/src/barretenberg/common/op_count.hpp b/barretenberg/cpp/src/barretenberg/common/op_count.hpp new file mode 100644 index 00000000000..57600138fe2 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/op_count.hpp @@ -0,0 +1,87 @@ + +#pragma once + +#ifndef BB_USE_OP_COUNT +// require a semicolon to appease formatters +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_OP_COUNT_TRACK() (void)0 +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_OP_COUNT_TRACK_NAME(name) (void)0 +#else +/** + * Provides an abstraction that counts operations based on function names. + * For efficiency, we spread out counts across threads. + */ + +#include "barretenberg/common/compiler_hints.hpp" +#include +#include +#include +#include +#include +#include +#include +namespace bb::detail { +// Compile-time string +// See e.g. https://www.reddit.com/r/cpp_questions/comments/pumi9r/does_c20_not_support_string_literals_as_template/ +template struct OperationLabel { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + constexpr OperationLabel(const char (&str)[N]) + { + for (std::size_t i = 0; i < N; ++i) { + value[i] = str[i]; + } + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) + char value[N]; +}; + +// Contains all statically known op counts +struct GlobalOpCountContainer { + public: + struct Entry { + std::string key; + std::string thread_id; + std::size_t* count; + }; + std::mutex mutex; + std::vector counts; + void print() const; + // NOTE: Should be called when other threads aren't active + void clear(); + void add_entry(const char* key, std::size_t* count); + std::map get_aggregate_counts() const; +}; + +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +extern GlobalOpCountContainer GLOBAL_OP_COUNTS; + +template struct GlobalOpCount { + public: + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + static thread_local std::size_t* thread_local_count; + + static constexpr void increment_op_count() + { + if (std::is_constant_evaluated()) { + // We do nothing if the compiler tries to run this + return; + } + if (BB_UNLIKELY(thread_local_count == nullptr)) { + thread_local_count = new std::size_t(); + GLOBAL_OP_COUNTS.add_entry(Op.value, thread_local_count); + } + (*thread_local_count)++; + } +}; +// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) +template thread_local std::size_t* GlobalOpCount::thread_local_count; + +} // namespace bb::detail + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_OP_COUNT_TRACK() bb::detail::GlobalOpCount<__func__>::increment_op_count() +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_OP_COUNT_TRACK_NAME(name) bb::detail::GlobalOpCount::increment_op_count() +#endif \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/op_count_google_bench.hpp b/barretenberg/cpp/src/barretenberg/common/op_count_google_bench.hpp new file mode 100644 index 00000000000..f872df1544b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/common/op_count_google_bench.hpp @@ -0,0 +1,50 @@ + +#pragma once +#include + +#ifndef BB_USE_OP_COUNT +namespace bb { +struct GoogleBenchOpCountReporter { + GoogleBenchOpCountReporter(::benchmark::State& state) + { + // unused, we don't have op counts on + (void)state; + } +}; +}; // namespace bb +// require a semicolon to appease formatters +#define BB_REPORT_OP_COUNT_IN_BENCH(state) (void)0 +#define BB_REPORT_OP_COUNT_BENCH_CANCEL() (void)0 +#else +#include "op_count.hpp" +namespace bb { +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +struct GoogleBenchOpCountReporter { + // We allow having a ref member as this only lives inside a function frame + ::benchmark::State& state; + bool cancelled = false; + GoogleBenchOpCountReporter(::benchmark::State& state) + : state(state) + { + // Intent: Clear when we enter the state loop + bb::detail::GLOBAL_OP_COUNTS.clear(); + } + ~GoogleBenchOpCountReporter() + { + // Allow for conditional reporting + if (cancelled) { + return; + } + // Intent: Collect results when we exit the state loop + for (auto& entry : bb::detail::GLOBAL_OP_COUNTS.get_aggregate_counts()) { + state.counters[entry.first] = static_cast(entry.second); + } + } +}; +// Allow for integration with google benchmark user-defined counters +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_REPORT_OP_COUNT_IN_BENCH(state) GoogleBenchOpCountReporter __bb_report_op_count_in_bench{ state }; +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define BB_REPORT_OP_COUNT_BENCH_CANCEL() __bb_report_op_count_in_bench.cancelled = true; +}; // namespace bb +#endif \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/parallel_for_mutex_pool.cpp b/barretenberg/cpp/src/barretenberg/common/parallel_for_mutex_pool.cpp index d3a1afac509..7c85c03927c 100644 --- a/barretenberg/cpp/src/barretenberg/common/parallel_for_mutex_pool.cpp +++ b/barretenberg/cpp/src/barretenberg/common/parallel_for_mutex_pool.cpp @@ -52,7 +52,7 @@ class ThreadPool { std::condition_variable complete_condition_; bool stop = false; - BBERG_NO_PROFILE void worker_loop(size_t thread_index); + BB_NO_PROFILE void worker_loop(size_t thread_index); void do_iterations() { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index a967b01b647..7d48827ef27 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -268,7 +268,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .result = arg.output, .opcode = BigIntOperationType::Add, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, .rhs = arg.rhs, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 02adc0e63e6..2c6bea75698 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -5,221 +5,307 @@ namespace Circuit { -struct Witness { - uint32_t value; - - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); -}; - -struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; - - friend bool operator==(const FunctionInput&, const FunctionInput&); - std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); -}; - -struct BlackBoxFuncCall { - - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; +struct BinaryFieldOp { - friend bool operator==(const AND&, const AND&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const XOR&, const XOR&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct RANGE { - Circuit::FunctionInput input; + struct Div { + friend bool operator==(const Div&, const Div&); + std::vector bincodeSerialize() const; + static Div bincodeDeserialize(std::vector); + }; - friend bool operator==(const RANGE&, const RANGE&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; + std::variant value; - friend bool operator==(const SHA256&, const SHA256&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + std::vector bincodeSerialize() const; + static BinaryFieldOp bincodeDeserialize(std::vector); +}; + +struct BinaryIntOp { + + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct Blake2s { - std::vector inputs; - std::vector outputs; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake2s&, const Blake2s&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct Blake3 { - std::vector inputs; - std::vector outputs; + struct SignedDiv { + friend bool operator==(const SignedDiv&, const SignedDiv&); + std::vector bincodeSerialize() const; + static SignedDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const Blake3&, const Blake3&); + struct UnsignedDiv { + friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static UnsignedDiv bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; + struct Equals { + friend bool operator==(const Equals&, const Equals&); + std::vector bincodeSerialize() const; + static Equals bincodeDeserialize(std::vector); + }; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + struct And { + friend bool operator==(const And&, const And&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static And bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; - friend bool operator==(const PedersenHash&, const PedersenHash&); + struct Xor { + friend bool operator==(const Xor&, const Xor&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Xor bincodeDeserialize(std::vector); }; - struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + struct Shr { + friend bool operator==(const Shr&, const Shr&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Shr bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::variant value; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); +}; + +struct MemoryAddress { + uint64_t value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); + std::vector bincodeSerialize() const; + static MemoryAddress bincodeDeserialize(std::vector); +}; + +struct HeapArray { + Circuit::MemoryAddress pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); +}; + +struct HeapVector { + Circuit::MemoryAddress pointer; + Circuit::MemoryAddress size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); +}; + +struct BlackBoxOp { + + struct Sha256 { + Circuit::HeapVector message; + Circuit::HeapArray output; + + friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static Sha256 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; + struct Blake2s { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + struct Blake3 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; struct Keccak256 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; static Keccak256 bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; - - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); - std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); - }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; static Keccakf1600 bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; - - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); - std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + struct EcdsaSecp256k1 { + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; + + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256k1 bincodeDeserialize(std::vector); + }; + + struct EcdsaSecp256r1 { + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; + + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256r1 bincodeDeserialize(std::vector); + }; + + struct SchnorrVerify { + Circuit::MemoryAddress public_key_x; + Circuit::MemoryAddress public_key_y; + Circuit::HeapVector message; + Circuit::HeapVector signature; + Circuit::MemoryAddress result; + + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + std::vector bincodeSerialize() const; + static SchnorrVerify bincodeDeserialize(std::vector); + }; + + struct PedersenCommitment { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::HeapArray output; + + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + std::vector bincodeSerialize() const; + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::MemoryAddress output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); + }; + + struct FixedBaseScalarMul { + Circuit::MemoryAddress low; + Circuit::MemoryAddress high; + Circuit::HeapArray result; + + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; + + struct EmbeddedCurveAdd { + Circuit::MemoryAddress input1_x; + Circuit::MemoryAddress input1_y; + Circuit::MemoryAddress input2_x; + Circuit::MemoryAddress input2_y; + Circuit::HeapArray result; + + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + std::vector bincodeSerialize() const; + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct BigIntSub { + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -227,9 +313,9 @@ struct BlackBoxFuncCall { }; struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -237,9 +323,9 @@ struct BlackBoxFuncCall { }; struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + Circuit::HeapVector inputs; + Circuit::HeapVector modulus; + Circuit::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -247,8 +333,8 @@ struct BlackBoxFuncCall { }; struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + Circuit::MemoryAddress input; + Circuit::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -256,9 +342,9 @@ struct BlackBoxFuncCall { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + Circuit::HeapVector message; + Circuit::HeapArray output; + Circuit::MemoryAddress len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -266,34 +352,29 @@ struct BlackBoxFuncCall { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); -}; - -struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); -}; - -struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; - - friend bool operator==(const Expression&, const Expression&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; -struct BrilligInputs { +struct HeapValueType; - struct Single { - Circuit::Expression value; +struct HeapValueType { - friend bool operator==(const Single&, const Single&); + struct Simple { + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; struct Array { - std::vector value; + std::vector value_types; + uint64_t size; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; static Array bincodeDeserialize(std::vector); }; - std::variant value; + struct Vector { + std::vector value_types; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const Vector&, const Vector&); + std::vector bincodeSerialize() const; + static Vector bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const HeapValueType&, const HeapValueType&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static HeapValueType bincodeDeserialize(std::vector); }; -struct BinaryFieldOp { +struct Value { + std::string inner; - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + friend bool operator==(const Value&, const Value&); + std::vector bincodeSerialize() const; + static Value bincodeDeserialize(std::vector); +}; - struct Sub { - friend bool operator==(const Sub&, const Sub&); - std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); - }; +struct ValueOrArray { - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct MemoryAddress { + Circuit::MemoryAddress value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct HeapArray { + Circuit::HeapArray value; + + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct HeapVector { + Circuit::HeapVector value; + + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const ValueOrArray&, const ValueOrArray&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static ValueOrArray bincodeDeserialize(std::vector); }; -struct BinaryIntOp { +struct BrilligOpcode { - struct Add { - friend bool operator==(const Add&, const Add&); + struct BinaryFieldOp { + Circuit::MemoryAddress destination; + Circuit::BinaryFieldOp op; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct BinaryIntOp { + Circuit::MemoryAddress destination; + Circuit::BinaryIntOp op; + uint32_t bit_size; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct Cast { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; + uint32_t bit_size; + + friend bool operator==(const Cast&, const Cast&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static Cast bincodeDeserialize(std::vector); }; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); + struct JumpIfNot { + Circuit::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + struct JumpIf { + Circuit::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Jump { + uint64_t location; + + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct CalldataCopy { + Circuit::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; + + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct Call { + uint64_t location; + + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct Const { + Circuit::MemoryAddress destination; + uint32_t bit_size; + Circuit::Value value; + + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct Or { - friend bool operator==(const Or&, const Or&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; + + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + struct Mov { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; + + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct Load { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source_pointer; + + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - std::variant value; + struct Store { + Circuit::MemoryAddress destination_pointer; + Circuit::MemoryAddress source; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); -}; + friend bool operator==(const Store&, const Store&); + std::vector bincodeSerialize() const; + static Store bincodeDeserialize(std::vector); + }; -struct MemoryAddress { - uint64_t value; + struct BlackBox { + Circuit::BlackBoxOp value; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); + friend bool operator==(const BlackBox&, const BlackBox&); + std::vector bincodeSerialize() const; + static BlackBox bincodeDeserialize(std::vector); + }; + + struct Trap { + friend bool operator==(const Trap&, const Trap&); + std::vector bincodeSerialize() const; + static Trap bincodeDeserialize(std::vector); + }; + + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; + + friend bool operator==(const Stop&, const Stop&); + std::vector bincodeSerialize() const; + static Stop bincodeDeserialize(std::vector); + }; + + std::variant + value; + + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); + static BrilligOpcode bincodeDeserialize(std::vector); }; -struct HeapArray { - Circuit::MemoryAddress pointer; - uint64_t size; +struct Witness { + uint32_t value; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Witness&, const Witness&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static Witness bincodeDeserialize(std::vector); }; -struct HeapVector { - Circuit::MemoryAddress pointer; - Circuit::MemoryAddress size; +struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const FunctionInput&, const FunctionInput&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static FunctionInput bincodeDeserialize(std::vector); }; -struct BlackBoxOp { +struct BlackBoxFuncCall { - struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); + }; + + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const XOR&, const XOR&); + std::vector bincodeSerialize() const; + static XOR bincodeDeserialize(std::vector); + }; + + struct RANGE { + Circuit::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); + std::vector bincodeSerialize() const; + static RANGE bincodeDeserialize(std::vector); + }; + + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); + std::vector bincodeSerialize() const; + static SHA256 bincodeDeserialize(std::vector); }; struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -523,38 +710,52 @@ struct BlackBoxOp { }; struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -562,95 +763,102 @@ struct BlackBoxOp { }; struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::MemoryAddress public_key_x; - Circuit::MemoryAddress public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::MemoryAddress result; + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::HeapArray output; + struct EmbeddedCurveAdd { + Circuit::FunctionInput input1_x; + Circuit::FunctionInput input1_y; + Circuit::FunctionInput input2_x; + Circuit::FunctionInput input2_y; + std::array outputs; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::MemoryAddress output; + struct Keccak256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::MemoryAddress low; - Circuit::MemoryAddress high; - Circuit::HeapArray result; + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::MemoryAddress input1_x; - Circuit::MemoryAddress input1_y; - Circuit::MemoryAddress input2_x; - Circuit::MemoryAddress input2_y; - Circuit::HeapArray result; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); + }; + + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::FunctionInput key_hash; + + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + std::vector bincodeSerialize() const; + static RecursiveAggregation bincodeDeserialize(std::vector); }; struct BigIntAdd { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -658,9 +866,9 @@ struct BlackBoxOp { }; struct BigIntDiv { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -668,9 +876,9 @@ struct BlackBoxOp { }; struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::MemoryAddress output; + std::vector inputs; + std::vector modulus; + uint32_t output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -678,8 +886,8 @@ struct BlackBoxOp { }; struct BigIntToLeBytes { - Circuit::MemoryAddress input; - Circuit::HeapVector output; + uint32_t input; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -687,9 +895,9 @@ struct BlackBoxOp { }; struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::MemoryAddress len; + std::vector inputs; + std::vector outputs; + uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -697,29 +905,34 @@ struct BlackBoxOp { }; struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + std::vector inputs; + std::vector hash_values; + std::vector outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; -struct Value { - std::string inner; +struct BlockId { + uint32_t value; - friend bool operator==(const Value&, const Value&); + friend bool operator==(const BlockId&, const BlockId&); std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); + static BlockId bincodeDeserialize(std::vector); }; -struct ValueOrArray { +struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - struct MemoryAddress { - Circuit::MemoryAddress value; + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); +}; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); +struct BrilligInputs { + + struct Single { + Circuit::Expression value; + + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct HeapArray { - Circuit::HeapArray value; + struct Array { + std::vector value; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::HeapVector value; + struct MemoryArray { + Circuit::BlockId value; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const ValueOrArray&, const ValueOrArray&); + friend bool operator==(const BrilligInputs&, const BrilligInputs&); std::vector bincodeSerialize() const; - static ValueOrArray bincodeDeserialize(std::vector); + static BrilligInputs bincodeDeserialize(std::vector); }; -struct BrilligOpcode { +struct BrilligOutputs { - struct BinaryFieldOp { - Circuit::MemoryAddress destination; - Circuit::BinaryFieldOp op; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + struct Simple { + Circuit::Witness value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Circuit::MemoryAddress destination; - Circuit::BinaryIntOp op; - uint32_t bit_size; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + struct Array { + std::vector value; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Circuit::MemoryAddress condition; - uint64_t location; + std::variant value; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); - std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); + std::vector bincodeSerialize() const; + static BrilligOutputs bincodeDeserialize(std::vector); +}; - struct JumpIf { - Circuit::MemoryAddress condition; - uint64_t location; +struct Brillig { + std::vector inputs; + std::vector outputs; + std::vector bytecode; + std::optional predicate; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const Brillig&, const Brillig&); + std::vector bincodeSerialize() const; + static Brillig bincodeDeserialize(std::vector); +}; + +struct Directive { + + struct ToLeRadix { + Circuit::Expression a; + std::vector b; + uint32_t radix; + + friend bool operator==(const ToLeRadix&, const ToLeRadix&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); - }; - - struct Jump { - uint64_t location; - - friend bool operator==(const Jump&, const Jump&); - std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); - }; - - struct CalldataCopy { - Circuit::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; - - friend bool operator==(const CalldataCopy&, const CalldataCopy&); - std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); - }; - - struct Call { - uint64_t location; - - friend bool operator==(const Call&, const Call&); - std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); - }; - - struct Const { - Circuit::MemoryAddress destination; - Circuit::Value value; - - friend bool operator==(const Const&, const Const&); - std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); - }; - - struct Return { - friend bool operator==(const Return&, const Return&); - std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); - }; - - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector inputs; - - friend bool operator==(const ForeignCall&, const ForeignCall&); - std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); - }; - - struct Mov { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; - - friend bool operator==(const Mov&, const Mov&); - std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); - }; - - struct Load { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source_pointer; - - friend bool operator==(const Load&, const Load&); - std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); - }; - - struct Store { - Circuit::MemoryAddress destination_pointer; - Circuit::MemoryAddress source; - - friend bool operator==(const Store&, const Store&); - std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); - }; - - struct BlackBox { - Circuit::BlackBoxOp value; - - friend bool operator==(const BlackBox&, const BlackBox&); - std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); - }; - - struct Trap { - friend bool operator==(const Trap&, const Trap&); - std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); - }; - - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; - - friend bool operator==(const Stop&, const Stop&); - std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); - }; - - std::variant - value; - - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); - std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); -}; - -struct BrilligOutputs { - - struct Simple { - Circuit::Witness value; - - friend bool operator==(const Simple&, const Simple&); - std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); - }; - - struct Array { - std::vector value; - - friend bool operator==(const Array&, const Array&); - std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); - std::vector bincodeSerialize() const; - static BrilligOutputs bincodeDeserialize(std::vector); -}; - -struct Brillig { - std::vector inputs; - std::vector outputs; - std::vector bytecode; - std::optional predicate; - - friend bool operator==(const Brillig&, const Brillig&); - std::vector bincodeSerialize() const; - static Brillig bincodeDeserialize(std::vector); -}; - -struct Directive { - - struct ToLeRadix { - Circuit::Expression a; - std::vector b; - uint32_t radix; - - friend bool operator==(const ToLeRadix&, const ToLeRadix&); - std::vector bincodeSerialize() const; - static ToLeRadix bincodeDeserialize(std::vector); + static ToLeRadix bincodeDeserialize(std::vector); }; struct PermutationSort { @@ -1077,6 +1133,29 @@ struct Opcode { static Opcode bincodeDeserialize(std::vector); }; +struct ExpressionWidth { + + struct Unbounded { + friend bool operator==(const Unbounded&, const Unbounded&); + std::vector bincodeSerialize() const; + static Unbounded bincodeDeserialize(std::vector); + }; + + struct Bounded { + uint64_t width; + + friend bool operator==(const Bounded&, const Bounded&); + std::vector bincodeSerialize() const; + static Bounded bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ExpressionWidth&, const ExpressionWidth&); + std::vector bincodeSerialize() const; + static ExpressionWidth bincodeDeserialize(std::vector); +}; + struct OpcodeLocation { struct Acir { @@ -1114,6 +1193,7 @@ struct PublicInputs { struct Circuit { uint32_t current_witness_index; std::vector opcodes; + ExpressionWidth expression_width; std::vector private_parameters; PublicInputs public_parameters; PublicInputs return_values; @@ -1125,29 +1205,365 @@ struct Circuit { static Circuit bincodeDeserialize(std::vector); }; -} // end of namespace Circuit +} // end of namespace Circuit + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp& lhs, const BinaryFieldOp& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector BinaryFieldOp::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp& obj, Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + Circuit::BinaryFieldOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::Add& lhs, const BinaryFieldOp::Add& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::Add::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::Add obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::Sub& lhs, const BinaryFieldOp::Sub& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::Sub::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::Sub obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::Mul& lhs, const BinaryFieldOp::Mul& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::Mul::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::Mul obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::Div& lhs, const BinaryFieldOp::Div& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::Div::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::Div obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::Equals& lhs, const BinaryFieldOp::Equals& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::Equals::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::Equals obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryIntOp& lhs, const BinaryIntOp& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector BinaryIntOp::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp& obj, Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + Circuit::BinaryIntOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryIntOp::Add& lhs, const BinaryIntOp::Add& rhs) +{ + return true; +} + +inline std::vector BinaryIntOp::Add::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::BinaryIntOp::Add obj; + return obj; +} namespace Circuit { -inline bool operator==(const BinaryFieldOp& lhs, const BinaryFieldOp& rhs) +inline bool operator==(const BinaryIntOp::Sub& lhs, const BinaryIntOp::Sub& rhs) { - if (!(lhs.value == rhs.value)) { - return false; - } return true; } -inline std::vector BinaryFieldOp::bincodeSerialize() const +inline std::vector BinaryIntOp::Sub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1158,42 +1574,36 @@ inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector inpu template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); -} +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub& obj, + Serializer& serializer) +{} template <> template -Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BinaryFieldOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BinaryIntOp::Sub obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryFieldOp::Add& lhs, const BinaryFieldOp::Add& rhs) +inline bool operator==(const BinaryIntOp::Mul& lhs, const BinaryIntOp::Mul& rhs) { return true; } -inline std::vector BinaryFieldOp::Add::bincodeSerialize() const +inline std::vector BinaryIntOp::Mul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1204,36 +1614,36 @@ inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryFieldOp::Add obj; + Circuit::BinaryIntOp::Mul obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryFieldOp::Sub& lhs, const BinaryFieldOp::Sub& rhs) +inline bool operator==(const BinaryIntOp::SignedDiv& lhs, const BinaryIntOp::SignedDiv& rhs) { return true; } -inline std::vector BinaryFieldOp::Sub::bincodeSerialize() const +inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector input) +inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1244,36 +1654,37 @@ inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryFieldOp::Sub obj; + Circuit::BinaryIntOp::SignedDiv obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryFieldOp::Mul& lhs, const BinaryFieldOp::Mul& rhs) +inline bool operator==(const BinaryIntOp::UnsignedDiv& lhs, const BinaryIntOp::UnsignedDiv& rhs) { return true; } -inline std::vector BinaryFieldOp::Mul::bincodeSerialize() const +inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector input) +inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1284,36 +1695,37 @@ inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryFieldOp::Mul obj; + Circuit::BinaryIntOp::UnsignedDiv obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryFieldOp::Div& lhs, const BinaryFieldOp::Div& rhs) +inline bool operator==(const BinaryIntOp::Equals& lhs, const BinaryIntOp::Equals& rhs) { return true; } -inline std::vector BinaryFieldOp::Div::bincodeSerialize() const +inline std::vector BinaryIntOp::Equals::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1324,36 +1736,37 @@ inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryFieldOp::Div obj; + Circuit::BinaryIntOp::Equals obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryFieldOp::Equals& lhs, const BinaryFieldOp::Equals& rhs) +inline bool operator==(const BinaryIntOp::LessThan& lhs, const BinaryIntOp::LessThan& rhs) { return true; } -inline std::vector BinaryFieldOp::Equals::bincodeSerialize() const +inline std::vector BinaryIntOp::LessThan::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vector input) +inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1364,40 +1777,37 @@ inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals& obj, +void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize( +Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryFieldOp::Equals obj; + Circuit::BinaryIntOp::LessThan obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp& lhs, const BinaryIntOp& rhs) +inline bool operator==(const BinaryIntOp::LessThanEquals& lhs, const BinaryIntOp::LessThanEquals& rhs) { - if (!(lhs.value == rhs.value)) { - return false; - } return true; } -inline std::vector BinaryIntOp::bincodeSerialize() const +inline std::vector BinaryIntOp::LessThanEquals::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) +inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1408,42 +1818,77 @@ inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BinaryIntOp::LessThanEquals& obj, Serializer& serializer) +{} + +template <> +template +Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize( + Deserializer& deserializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); + Circuit::BinaryIntOp::LessThanEquals obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryIntOp::And& lhs, const BinaryIntOp::And& rhs) +{ + return true; +} + +inline std::vector BinaryIntOp::And::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; } +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryIntOp::And& obj, + Serializer& serializer) +{} + template <> template -Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BinaryIntOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BinaryIntOp::And obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Add& lhs, const BinaryIntOp::Add& rhs) +inline bool operator==(const BinaryIntOp::Or& lhs, const BinaryIntOp::Or& rhs) { return true; } -inline std::vector BinaryIntOp::Add::bincodeSerialize() const +inline std::vector BinaryIntOp::Or::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1454,36 +1899,36 @@ inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Add obj; + Circuit::BinaryIntOp::Or obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Sub& lhs, const BinaryIntOp::Sub& rhs) +inline bool operator==(const BinaryIntOp::Xor& lhs, const BinaryIntOp::Xor& rhs) { return true; } -inline std::vector BinaryIntOp::Sub::bincodeSerialize() const +inline std::vector BinaryIntOp::Xor::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1494,36 +1939,36 @@ inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub& obj, +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Sub obj; + Circuit::BinaryIntOp::Xor obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Mul& lhs, const BinaryIntOp::Mul& rhs) +inline bool operator==(const BinaryIntOp::Shl& lhs, const BinaryIntOp::Shl& rhs) { return true; } -inline std::vector BinaryIntOp::Mul::bincodeSerialize() const +inline std::vector BinaryIntOp::Shl::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1534,36 +1979,36 @@ inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul& obj, +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Mul obj; + Circuit::BinaryIntOp::Shl obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::SignedDiv& lhs, const BinaryIntOp::SignedDiv& rhs) +inline bool operator==(const BinaryIntOp::Shr& lhs, const BinaryIntOp::Shr& rhs) { return true; } -inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const +inline std::vector BinaryIntOp::Shr::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1574,37 +2019,39 @@ inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::ve template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::SignedDiv obj; + Circuit::BinaryIntOp::Shr obj; return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::UnsignedDiv& lhs, const BinaryIntOp::UnsignedDiv& rhs) +inline bool operator==(const BlackBoxFuncCall& lhs, const BlackBoxFuncCall& rhs) { + if (!(lhs.value == rhs.value)) { + return false; + } return true; } -inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1615,37 +2062,52 @@ inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall& obj, + Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} template <> template -Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::UnsignedDiv obj; + deserializer.increase_container_depth(); + Circuit::BlackBoxFuncCall obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Equals& lhs, const BinaryIntOp::Equals& rhs) +inline bool operator==(const BlackBoxFuncCall::AND& lhs, const BlackBoxFuncCall::AND& rhs) { + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { + return false; + } + if (!(lhs.output == rhs.output)) { + return false; + } return true; } -inline std::vector BinaryIntOp::Equals::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::AND::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1656,37 +2118,53 @@ inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); +} template <> template -Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::Equals obj; + Circuit::BlackBoxFuncCall::AND obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::LessThan& lhs, const BinaryIntOp::LessThan& rhs) +inline bool operator==(const BlackBoxFuncCall::XOR& lhs, const BlackBoxFuncCall::XOR& rhs) { + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { + return false; + } + if (!(lhs.output == rhs.output)) { + return false; + } return true; } -inline std::vector BinaryIntOp::LessThan::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::XOR::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1697,37 +2175,47 @@ inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan& obj, +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR& obj, Serializer& serializer) -{} +{ + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); +} template <> template -Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::LessThan obj; + Circuit::BlackBoxFuncCall::XOR obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::LessThanEquals& lhs, const BinaryIntOp::LessThanEquals& rhs) +inline bool operator==(const BlackBoxFuncCall::RANGE& lhs, const BlackBoxFuncCall::RANGE& rhs) { + if (!(lhs.input == rhs.input)) { + return false; + } return true; } -inline std::vector BinaryIntOp::LessThanEquals::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::RANGE::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1738,37 +2226,46 @@ inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BinaryIntOp::LessThanEquals& obj, Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.input, serializer); +} template <> template -Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::LessThanEquals obj; + Circuit::BlackBoxFuncCall::RANGE obj; + obj.input = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::And& lhs, const BinaryIntOp::And& rhs) +inline bool operator==(const BlackBoxFuncCall::SHA256& lhs, const BlackBoxFuncCall::SHA256& rhs) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } return true; } -inline std::vector BinaryIntOp::And::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::SHA256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1779,36 +2276,48 @@ inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::And& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} template <> template -Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryIntOp::And obj; + Circuit::BlackBoxFuncCall::SHA256 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Or& lhs, const BinaryIntOp::Or& rhs) +inline bool operator==(const BlackBoxFuncCall::Blake2s& lhs, const BlackBoxFuncCall::Blake2s& rhs) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } return true; } -inline std::vector BinaryIntOp::Or::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Blake2s::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1819,36 +2328,48 @@ inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} template <> template -Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryIntOp::Or obj; + Circuit::BlackBoxFuncCall::Blake2s obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Xor& lhs, const BinaryIntOp::Xor& rhs) +inline bool operator==(const BlackBoxFuncCall::Blake3& lhs, const BlackBoxFuncCall::Blake3& rhs) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } return true; } -inline std::vector BinaryIntOp::Xor::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Blake3::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1859,36 +2380,57 @@ inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} template <> template -Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryIntOp::Xor obj; + Circuit::BlackBoxFuncCall::Blake3 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Shl& lhs, const BinaryIntOp::Shl& rhs) +inline bool operator==(const BlackBoxFuncCall::SchnorrVerify& lhs, const BlackBoxFuncCall::SchnorrVerify& rhs) { + if (!(lhs.public_key_x == rhs.public_key_x)) { + return false; + } + if (!(lhs.public_key_y == rhs.public_key_y)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.message == rhs.message)) { + return false; + } + if (!(lhs.output == rhs.output)) { + return false; + } return true; } -inline std::vector BinaryIntOp::Shl::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::SchnorrVerify::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1899,36 +2441,58 @@ inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::SchnorrVerify& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.output, serializer); +} template <> template -Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BinaryIntOp::Shl obj; + Circuit::BlackBoxFuncCall::SchnorrVerify obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.message = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BinaryIntOp::Shr& lhs, const BinaryIntOp::Shr& rhs) +inline bool operator==(const BlackBoxFuncCall::PedersenCommitment& lhs, const BlackBoxFuncCall::PedersenCommitment& rhs) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.domain_separator == rhs.domain_separator)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } return true; } -inline std::vector BinaryIntOp::Shr::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1939,39 +2503,53 @@ inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::PedersenCommitment& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} template <> template -Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable< + Circuit::BlackBoxFuncCall::PedersenCommitment>::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Shr obj; + Circuit::BlackBoxFuncCall::PedersenCommitment obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall& lhs, const BlackBoxFuncCall& rhs) +inline bool operator==(const BlackBoxFuncCall::PedersenHash& lhs, const BlackBoxFuncCall::PedersenHash& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.domain_separator == rhs.domain_separator)) { + return false; + } + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1982,33 +2560,40 @@ inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::PedersenHash& obj, Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BlackBoxFuncCall obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BlackBoxFuncCall::PedersenHash obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::AND& lhs, const BlackBoxFuncCall::AND& rhs) +inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1& lhs, const BlackBoxFuncCall::EcdsaSecp256k1& rhs) { - if (!(lhs.lhs == rhs.lhs)) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.public_key_y == rhs.public_key_y)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -2017,17 +2602,17 @@ inline bool operator==(const BlackBoxFuncCall::AND& lhs, const BlackBoxFuncCall: return true; } -inline std::vector BlackBoxFuncCall::AND::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::EcdsaSecp256k1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2038,34 +2623,44 @@ inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::EcdsaSecp256k1& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.hashed_message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::AND obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.hashed_message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::XOR& lhs, const BlackBoxFuncCall::XOR& rhs) +inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256r1& lhs, const BlackBoxFuncCall::EcdsaSecp256r1& rhs) { - if (!(lhs.lhs == rhs.lhs)) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.public_key_y == rhs.public_key_y)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.hashed_message == rhs.hashed_message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -2074,17 +2669,17 @@ inline bool operator==(const BlackBoxFuncCall::XOR& lhs, const BlackBoxFuncCall: return true; } -inline std::vector BlackBoxFuncCall::XOR::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::EcdsaSecp256r1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::EcdsaSecp256r1 BlackBoxFuncCall::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2095,47 +2690,58 @@ inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::EcdsaSecp256r1& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.hashed_message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::XOR obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.hashed_message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::RANGE& lhs, const BlackBoxFuncCall::RANGE& rhs) +inline bool operator==(const BlackBoxFuncCall::FixedBaseScalarMul& lhs, const BlackBoxFuncCall::FixedBaseScalarMul& rhs) { - if (!(lhs.input == rhs.input)) { + if (!(lhs.low == rhs.low)) { + return false; + } + if (!(lhs.high == rhs.high)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::RANGE::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::FixedBaseScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2146,27 +2752,40 @@ inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std:: template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::FixedBaseScalarMul& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.low, serializer); + serde::Serializable::serialize(obj.high, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable< + Circuit::BlackBoxFuncCall::FixedBaseScalarMul>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::RANGE obj; - obj.input = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; + obj.low = serde::Deserializable::deserialize(deserializer); + obj.high = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::SHA256& lhs, const BlackBoxFuncCall::SHA256& rhs) +inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd& lhs, const BlackBoxFuncCall::EmbeddedCurveAdd& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.input1_x == rhs.input1_x)) { + return false; + } + if (!(lhs.input1_y == rhs.input1_y)) { + return false; + } + if (!(lhs.input2_x == rhs.input2_x)) { + return false; + } + if (!(lhs.input2_y == rhs.input2_y)) { return false; } if (!(lhs.outputs == rhs.outputs)) { @@ -2175,17 +2794,18 @@ inline bool operator==(const BlackBoxFuncCall::SHA256& lhs, const BlackBoxFuncCa return true; } -inline std::vector BlackBoxFuncCall::SHA256::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::EmbeddedCurveAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2196,27 +2816,33 @@ inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input1_x, serializer); + serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input2_x, serializer); + serde::Serializable::serialize(obj.input2_y, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< + Circuit::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::SHA256 obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; + obj.input1_x = serde::Deserializable::deserialize(deserializer); + obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input2_x = serde::Deserializable::deserialize(deserializer); + obj.input2_y = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Blake2s& lhs, const BlackBoxFuncCall::Blake2s& rhs) +inline bool operator==(const BlackBoxFuncCall::Keccak256& lhs, const BlackBoxFuncCall::Keccak256& rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; @@ -2227,17 +2853,17 @@ inline bool operator==(const BlackBoxFuncCall::Blake2s& lhs, const BlackBoxFuncC return true; } -inline std::vector BlackBoxFuncCall::Blake2s::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Keccak256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2248,8 +2874,8 @@ inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(s template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Keccak256& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -2257,10 +2883,10 @@ void serde::Serializable::serialize(const Ci template <> template -Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Blake2s obj; + Circuit::BlackBoxFuncCall::Keccak256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; @@ -2268,28 +2894,33 @@ Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable BlackBoxFuncCall::Blake3::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Keccak256VariableLength::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256VariableLength::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2300,57 +2931,50 @@ inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Keccak256VariableLength& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.var_message_size, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable< + Circuit::BlackBoxFuncCall::Keccak256VariableLength>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Blake3 obj; + Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::SchnorrVerify& lhs, const BlackBoxFuncCall::SchnorrVerify& rhs) +inline bool operator==(const BlackBoxFuncCall::Keccakf1600& lhs, const BlackBoxFuncCall::Keccakf1600& rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { - return false; - } - if (!(lhs.signature == rhs.signature)) { - return false; - } - if (!(lhs.message == rhs.message)) { + if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::SchnorrVerify::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2361,58 +2985,56 @@ inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeD template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::SchnorrVerify& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Keccakf1600& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::SchnorrVerify obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::Keccakf1600 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::PedersenCommitment& lhs, const BlackBoxFuncCall::PedersenCommitment& rhs) +inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation& lhs, + const BlackBoxFuncCall::RecursiveAggregation& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.verification_key == rhs.verification_key)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { + if (!(lhs.proof == rhs.proof)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.public_inputs == rhs.public_inputs)) { + return false; + } + if (!(lhs.key_hash == rhs.key_hash)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::RecursiveAggregation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::bincodeDeserialize( +inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggregation::bincodeDeserialize( std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2423,34 +3045,36 @@ inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::PedersenCommitment& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::RecursiveAggregation& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.verification_key, serializer); + serde::Serializable::serialize(obj.proof, serializer); + serde::Serializable::serialize(obj.public_inputs, serializer); + serde::Serializable::serialize(obj.key_hash, serializer); } template <> template -Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable< - Circuit::BlackBoxFuncCall::PedersenCommitment>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable< + Circuit::BlackBoxFuncCall::RecursiveAggregation>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::RecursiveAggregation obj; + obj.verification_key = serde::Deserializable::deserialize(deserializer); + obj.proof = serde::Deserializable::deserialize(deserializer); + obj.public_inputs = serde::Deserializable::deserialize(deserializer); + obj.key_hash = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::PedersenHash& lhs, const BlackBoxFuncCall::PedersenHash& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntAdd& lhs, const BlackBoxFuncCall::BigIntAdd& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { @@ -2459,17 +3083,17 @@ inline bool operator==(const BlackBoxFuncCall::PedersenHash& lhs, const BlackBox return true; } -inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2480,40 +3104,34 @@ inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDes template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::PedersenHash& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntAdd& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntAdd obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1& lhs, const BlackBoxFuncCall::EcdsaSecp256k1& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntSub& lhs, const BlackBoxFuncCall::BigIntSub& rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { - return false; - } - if (!(lhs.signature == rhs.signature)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.hashed_message == rhs.hashed_message)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { @@ -2522,17 +3140,17 @@ inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1& lhs, const BlackB return true; } -inline std::vector BlackBoxFuncCall::EcdsaSecp256k1::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::BigIntSub BlackBoxFuncCall::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2543,44 +3161,34 @@ inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincod template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EcdsaSecp256k1& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntSub& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.hashed_message, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.hashed_message = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntSub obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256r1& lhs, const BlackBoxFuncCall::EcdsaSecp256r1& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntMul& lhs, const BlackBoxFuncCall::BigIntMul& rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { - return false; - } - if (!(lhs.signature == rhs.signature)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.hashed_message == rhs.hashed_message)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { @@ -2589,17 +3197,17 @@ inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256r1& lhs, const BlackB return true; } -inline std::vector BlackBoxFuncCall::EcdsaSecp256r1::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::EcdsaSecp256r1 BlackBoxFuncCall::EcdsaSecp256r1::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2610,58 +3218,53 @@ inline BlackBoxFuncCall::EcdsaSecp256r1 BlackBoxFuncCall::EcdsaSecp256r1::bincod template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EcdsaSecp256r1& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntMul& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.hashed_message, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize( +Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.hashed_message = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntMul obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::FixedBaseScalarMul& lhs, const BlackBoxFuncCall::FixedBaseScalarMul& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntDiv& lhs, const BlackBoxFuncCall::BigIntDiv& rhs) { - if (!(lhs.low == rhs.low)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.high == rhs.high)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::FixedBaseScalarMul::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul::bincodeDeserialize( - std::vector input) +inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2672,60 +3275,54 @@ inline BlackBoxFuncCall::FixedBaseScalarMul BlackBoxFuncCall::FixedBaseScalarMul template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::FixedBaseScalarMul& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntDiv& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); - serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable< - Circuit::BlackBoxFuncCall::FixedBaseScalarMul>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntDiv obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd& lhs, const BlackBoxFuncCall::EmbeddedCurveAdd& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes& lhs, const BlackBoxFuncCall::BigIntFromLeBytes& rhs) { - if (!(lhs.input1_x == rhs.input1_x)) { - return false; - } - if (!(lhs.input1_y == rhs.input1_y)) { - return false; - } - if (!(lhs.input2_x == rhs.input2_x)) { + if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.input2_y == rhs.input2_y)) { + if (!(lhs.modulus == rhs.modulus)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::EmbeddedCurveAdd::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntFromLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bincodeDeserialize( +inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes::bincodeDeserialize( std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2736,35 +3333,31 @@ inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bi template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntFromLeBytes& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); - serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.modulus, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable< + Circuit::BlackBoxFuncCall::BigIntFromLeBytes>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.modulus = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Keccak256& lhs, const BlackBoxFuncCall::Keccak256& rhs) +inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes& lhs, const BlackBoxFuncCall::BigIntToLeBytes& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.input == rhs.input)) { return false; } if (!(lhs.outputs == rhs.outputs)) { @@ -2773,17 +3366,18 @@ inline bool operator==(const BlackBoxFuncCall::Keccak256& lhs, const BlackBoxFun return true; } -inline std::vector BlackBoxFuncCall::Keccak256::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::BigIntToLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2794,53 +3388,53 @@ inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccak256& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::BigIntToLeBytes& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable< + Circuit::BlackBoxFuncCall::BigIntToLeBytes>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccak256 obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; + obj.input = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Keccak256VariableLength& lhs, - const BlackBoxFuncCall::Keccak256VariableLength& rhs) +inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation& lhs, + const BlackBoxFuncCall::Poseidon2Permutation& rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.var_message_size == rhs.var_message_size)) { + if (!(lhs.outputs == rhs.outputs)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.len == rhs.len)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::Keccak256VariableLength::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Poseidon2Permutation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256VariableLength::bincodeDeserialize( +inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permutation::bincodeDeserialize( std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2851,50 +3445,54 @@ inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256Vari template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccak256VariableLength& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Poseidon2Permutation& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.var_message_size, serializer); serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.len, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable< - Circuit::BlackBoxFuncCall::Keccak256VariableLength>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable< + Circuit::BlackBoxFuncCall::Poseidon2Permutation>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; + Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); + obj.len = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Keccakf1600& lhs, const BlackBoxFuncCall::Keccakf1600& rhs) +inline bool operator==(const BlackBoxFuncCall::Sha256Compression& lhs, const BlackBoxFuncCall::Sha256Compression& rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.hash_values == rhs.hash_values)) { + return false; + } if (!(lhs.outputs == rhs.outputs)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const +inline std::vector BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) +inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize( + std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2905,56 +3503,47 @@ inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeser template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccakf1600& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Sha256Compression& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable< + Circuit::BlackBoxFuncCall::Sha256Compression>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccakf1600 obj; + Circuit::BlackBoxFuncCall::Sha256Compression obj; obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation& lhs, - const BlackBoxFuncCall::RecursiveAggregation& rhs) +inline bool operator==(const BlackBoxOp& lhs, const BlackBoxOp& rhs) { - if (!(lhs.verification_key == rhs.verification_key)) { - return false; - } - if (!(lhs.proof == rhs.proof)) { - return false; - } - if (!(lhs.public_inputs == rhs.public_inputs)) { - return false; - } - if (!(lhs.key_hash == rhs.key_hash)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::RecursiveAggregation::bincodeSerialize() const +inline std::vector BlackBoxOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggregation::bincodeDeserialize( - std::vector input) +inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -2965,36 +3554,29 @@ inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggrega template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::RecursiveAggregation& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.verification_key, serializer); - serde::Serializable::serialize(obj.proof, serializer); - serde::Serializable::serialize(obj.public_inputs, serializer); - serde::Serializable::serialize(obj.key_hash, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable< - Circuit::BlackBoxFuncCall::RecursiveAggregation>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::RecursiveAggregation obj; - obj.verification_key = serde::Deserializable::deserialize(deserializer); - obj.proof = serde::Deserializable::deserialize(deserializer); - obj.public_inputs = serde::Deserializable::deserialize(deserializer); - obj.key_hash = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::BlackBoxOp obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntAdd& lhs, const BlackBoxFuncCall::BigIntAdd& rhs) +inline bool operator==(const BlackBoxOp::Sha256& lhs, const BlackBoxOp::Sha256& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3003,17 +3585,17 @@ inline bool operator==(const BlackBoxFuncCall::BigIntAdd& lhs, const BlackBoxFun return true; } -inline std::vector BlackBoxFuncCall::BigIntAdd::bincodeSerialize() const +inline std::vector BlackBoxOp::Sha256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3024,34 +3606,28 @@ inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntAdd& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntAdd obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Sha256 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntNeg& lhs, const BlackBoxFuncCall::BigIntNeg& rhs) +inline bool operator==(const BlackBoxOp::Blake2s& lhs, const BlackBoxOp::Blake2s& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3060,17 +3636,17 @@ inline bool operator==(const BlackBoxFuncCall::BigIntNeg& lhs, const BlackBoxFun return true; } -inline std::vector BlackBoxFuncCall::BigIntNeg::bincodeSerialize() const +inline std::vector BlackBoxOp::Blake2s::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntNeg BlackBoxFuncCall::BigIntNeg::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3081,34 +3657,29 @@ inline BlackBoxFuncCall::BigIntNeg BlackBoxFuncCall::BigIntNeg::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntNeg& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntNeg serde::Deserializable::deserialize( +Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntNeg obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Blake2s obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntMul& lhs, const BlackBoxFuncCall::BigIntMul& rhs) +inline bool operator==(const BlackBoxOp::Blake3& lhs, const BlackBoxOp::Blake3& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3117,17 +3688,17 @@ inline bool operator==(const BlackBoxFuncCall::BigIntMul& lhs, const BlackBoxFun return true; } -inline std::vector BlackBoxFuncCall::BigIntMul::bincodeSerialize() const +inline std::vector BlackBoxOp::Blake3::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3138,34 +3709,28 @@ inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntMul& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntMul obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Blake3 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntDiv& lhs, const BlackBoxFuncCall::BigIntDiv& rhs) +inline bool operator==(const BlackBoxOp::Keccak256& lhs, const BlackBoxOp::Keccak256& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3174,17 +3739,17 @@ inline bool operator==(const BlackBoxFuncCall::BigIntDiv& lhs, const BlackBoxFun return true; } -inline std::vector BlackBoxFuncCall::BigIntDiv::bincodeSerialize() const +inline std::vector BlackBoxOp::Keccak256::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3195,34 +3760,29 @@ inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntDiv& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize( +Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntDiv obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Keccak256 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes& lhs, const BlackBoxFuncCall::BigIntFromLeBytes& rhs) +inline bool operator==(const BlackBoxOp::Keccakf1600& lhs, const BlackBoxOp::Keccakf1600& rhs) { - if (!(lhs.inputs == rhs.inputs)) { - return false; - } - if (!(lhs.modulus == rhs.modulus)) { + if (!(lhs.message == rhs.message)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3231,18 +3791,17 @@ inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes& lhs, const Bla return true; } -inline std::vector BlackBoxFuncCall::BigIntFromLeBytes::bincodeSerialize() const +inline std::vector BlackBoxOp::Keccakf1600::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes::bincodeDeserialize( - std::vector input) +inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3253,51 +3812,57 @@ inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes:: template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntFromLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.modulus, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable< - Circuit::BlackBoxFuncCall::BigIntFromLeBytes>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.modulus = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Keccakf1600 obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes& lhs, const BlackBoxFuncCall::BigIntToLeBytes& rhs) +inline bool operator==(const BlackBoxOp::EcdsaSecp256k1& lhs, const BlackBoxOp::EcdsaSecp256k1& rhs) { - if (!(lhs.input == rhs.input)) { + if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.public_key_x == rhs.public_key_x)) { + return false; + } + if (!(lhs.public_key_y == rhs.public_key_y)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.result == rhs.result)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::BigIntToLeBytes::bincodeSerialize() const +inline std::vector BlackBoxOp::EcdsaSecp256k1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::bincodeDeserialize( - std::vector input) +inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3308,53 +3873,63 @@ inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::binc template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntToLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.hashed_msg, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable< - Circuit::BlackBoxFuncCall::BigIntToLeBytes>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::EcdsaSecp256k1 obj; + obj.hashed_msg = serde::Deserializable::deserialize(deserializer); + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation& lhs, - const BlackBoxFuncCall::Poseidon2Permutation& rhs) +inline bool operator==(const BlackBoxOp::EcdsaSecp256r1& lhs, const BlackBoxOp::EcdsaSecp256r1& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.len == rhs.len)) { + if (!(lhs.public_key_y == rhs.public_key_y)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.result == rhs.result)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::Poseidon2Permutation::bincodeSerialize() const +inline std::vector BlackBoxOp::EcdsaSecp256r1::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permutation::bincodeDeserialize( - std::vector input) +inline BlackBoxOp::EcdsaSecp256r1 BlackBoxOp::EcdsaSecp256r1::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3365,54 +3940,63 @@ inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permuta template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Poseidon2Permutation& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.outputs, serializer); - serde::Serializable::serialize(obj.len, serializer); + serde::Serializable::serialize(obj.hashed_msg, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable< - Circuit::BlackBoxFuncCall::Poseidon2Permutation>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - obj.len = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::EcdsaSecp256r1 obj; + obj.hashed_msg = serde::Deserializable::deserialize(deserializer); + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxFuncCall::Sha256Compression& lhs, const BlackBoxFuncCall::Sha256Compression& rhs) +inline bool operator==(const BlackBoxOp::SchnorrVerify& lhs, const BlackBoxOp::SchnorrVerify& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } - if (!(lhs.hash_values == rhs.hash_values)) { + if (!(lhs.public_key_y == rhs.public_key_y)) { return false; } - if (!(lhs.outputs == rhs.outputs)) { + if (!(lhs.message == rhs.message)) { + return false; + } + if (!(lhs.signature == rhs.signature)) { + return false; + } + if (!(lhs.result == rhs.result)) { return false; } return true; } -inline std::vector BlackBoxFuncCall::Sha256Compression::bincodeSerialize() const +inline std::vector BlackBoxOp::SchnorrVerify::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression::bincodeDeserialize( - std::vector input) +inline BlackBoxOp::SchnorrVerify BlackBoxOp::SchnorrVerify::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3423,47 +4007,57 @@ inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression:: template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Sha256Compression& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.hash_values, serializer); - serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.public_key_x, serializer); + serde::Serializable::serialize(obj.public_key_y, serializer); + serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.signature, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable< - Circuit::BlackBoxFuncCall::Sha256Compression>::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Sha256Compression obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.hash_values = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::SchnorrVerify obj; + obj.public_key_x = serde::Deserializable::deserialize(deserializer); + obj.public_key_y = serde::Deserializable::deserialize(deserializer); + obj.message = serde::Deserializable::deserialize(deserializer); + obj.signature = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp& lhs, const BlackBoxOp& rhs) +inline bool operator==(const BlackBoxOp::PedersenCommitment& lhs, const BlackBoxOp::PedersenCommitment& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.domain_separator == rhs.domain_separator)) { + return false; + } + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxOp::bincodeSerialize() const +inline std::vector BlackBoxOp::PedersenCommitment::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) +inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3474,29 +4068,34 @@ inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::PedersenCommitment& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BlackBoxOp obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BlackBoxOp::PedersenCommitment obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Sha256& lhs, const BlackBoxOp::Sha256& rhs) +inline bool operator==(const BlackBoxOp::PedersenHash& lhs, const BlackBoxOp::PedersenHash& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3505,17 +4104,17 @@ inline bool operator==(const BlackBoxOp::Sha256& lhs, const BlackBoxOp::Sha256& return true; } -inline std::vector BlackBoxOp::Sha256::bincodeSerialize() const +inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector input) +inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3526,47 +4125,53 @@ inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxOp::Sha256 obj; - obj.message = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::PedersenHash obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Blake2s& lhs, const BlackBoxOp::Blake2s& rhs) +inline bool operator==(const BlackBoxOp::FixedBaseScalarMul& lhs, const BlackBoxOp::FixedBaseScalarMul& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.low == rhs.low)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.high == rhs.high)) { + return false; + } + if (!(lhs.result == rhs.result)) { return false; } return true; } -inline std::vector BlackBoxOp::Blake2s::bincodeSerialize() const +inline std::vector BlackBoxOp::FixedBaseScalarMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector input) +inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3577,48 +4182,59 @@ inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::FixedBaseScalarMul& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.low, serializer); + serde::Serializable::serialize(obj.high, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize( +Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Blake2s obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::FixedBaseScalarMul obj; + obj.low = serde::Deserializable::deserialize(deserializer); + obj.high = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Blake3& lhs, const BlackBoxOp::Blake3& rhs) +inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd& lhs, const BlackBoxOp::EmbeddedCurveAdd& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.input1_x == rhs.input1_x)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.input1_y == rhs.input1_y)) { + return false; + } + if (!(lhs.input2_x == rhs.input2_x)) { + return false; + } + if (!(lhs.input2_y == rhs.input2_y)) { + return false; + } + if (!(lhs.result == rhs.result)) { return false; } return true; } -inline std::vector BlackBoxOp::Blake3::bincodeSerialize() const +inline std::vector BlackBoxOp::EmbeddedCurveAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector input) +inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3629,28 +4245,38 @@ inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::EmbeddedCurveAdd& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.input1_x, serializer); + serde::Serializable::serialize(obj.input1_y, serializer); + serde::Serializable::serialize(obj.input2_x, serializer); + serde::Serializable::serialize(obj.input2_y, serializer); + serde::Serializable::serialize(obj.result, serializer); } template <> template -Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BlackBoxOp::Blake3 obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::EmbeddedCurveAdd obj; + obj.input1_x = serde::Deserializable::deserialize(deserializer); + obj.input1_y = serde::Deserializable::deserialize(deserializer); + obj.input2_x = serde::Deserializable::deserialize(deserializer); + obj.input2_y = serde::Deserializable::deserialize(deserializer); + obj.result = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Keccak256& lhs, const BlackBoxOp::Keccak256& rhs) +inline bool operator==(const BlackBoxOp::BigIntAdd& lhs, const BlackBoxOp::BigIntAdd& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3659,17 +4285,17 @@ inline bool operator==(const BlackBoxOp::Keccak256& lhs, const BlackBoxOp::Kecca return true; } -inline std::vector BlackBoxOp::Keccak256::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntAdd::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntAdd BlackBoxOp::BigIntAdd::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3680,29 +4306,34 @@ inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256& obj, +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Keccak256 obj; - obj.message = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntAdd obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Keccakf1600& lhs, const BlackBoxOp::Keccakf1600& rhs) +inline bool operator==(const BlackBoxOp::BigIntSub& lhs, const BlackBoxOp::BigIntSub& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3711,17 +4342,17 @@ inline bool operator==(const BlackBoxOp::Keccakf1600& lhs, const BlackBoxOp::Kec return true; } -inline std::vector BlackBoxOp::Keccakf1600::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntSub BlackBoxOp::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3732,57 +4363,53 @@ inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std:: template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Keccakf1600 obj; - obj.message = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntSub obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::EcdsaSecp256k1& lhs, const BlackBoxOp::EcdsaSecp256k1& rhs) +inline bool operator==(const BlackBoxOp::BigIntMul& lhs, const BlackBoxOp::BigIntMul& rhs) { - if (!(lhs.hashed_msg == rhs.hashed_msg)) { - return false; - } - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.signature == rhs.signature)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.result == rhs.result)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxOp::EcdsaSecp256k1::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntMul::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3793,63 +4420,53 @@ inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.hashed_msg, serializer); - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256k1 obj; - obj.hashed_msg = serde::Deserializable::deserialize(deserializer); - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntMul obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::EcdsaSecp256r1& lhs, const BlackBoxOp::EcdsaSecp256r1& rhs) +inline bool operator==(const BlackBoxOp::BigIntDiv& lhs, const BlackBoxOp::BigIntDiv& rhs) { - if (!(lhs.hashed_msg == rhs.hashed_msg)) { - return false; - } - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { + if (!(lhs.lhs == rhs.lhs)) { return false; } - if (!(lhs.signature == rhs.signature)) { + if (!(lhs.rhs == rhs.rhs)) { return false; } - if (!(lhs.result == rhs.result)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxOp::EcdsaSecp256r1::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntDiv::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::EcdsaSecp256r1 BlackBoxOp::EcdsaSecp256r1::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3860,63 +4477,53 @@ inline BlackBoxOp::EcdsaSecp256r1 BlackBoxOp::EcdsaSecp256r1::bincodeDeserialize template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.hashed_msg, serializer); - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256r1 obj; - obj.hashed_msg = serde::Deserializable::deserialize(deserializer); - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntDiv obj; + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::SchnorrVerify& lhs, const BlackBoxOp::SchnorrVerify& rhs) +inline bool operator==(const BlackBoxOp::BigIntFromLeBytes& lhs, const BlackBoxOp::BigIntFromLeBytes& rhs) { - if (!(lhs.public_key_x == rhs.public_key_x)) { - return false; - } - if (!(lhs.public_key_y == rhs.public_key_y)) { - return false; - } - if (!(lhs.message == rhs.message)) { + if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.signature == rhs.signature)) { + if (!(lhs.modulus == rhs.modulus)) { return false; } - if (!(lhs.result == rhs.result)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxOp::SchnorrVerify::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntFromLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::SchnorrVerify BlackBoxOp::SchnorrVerify::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3927,38 +4534,31 @@ inline BlackBoxOp::SchnorrVerify BlackBoxOp::SchnorrVerify::bincodeDeserialize(s template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::BigIntFromLeBytes& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.public_key_x, serializer); - serde::Serializable::serialize(obj.public_key_y, serializer); - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.signature, serializer); - serde::Serializable::serialize(obj.result, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.modulus, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::SchnorrVerify obj; - obj.public_key_x = serde::Deserializable::deserialize(deserializer); - obj.public_key_y = serde::Deserializable::deserialize(deserializer); - obj.message = serde::Deserializable::deserialize(deserializer); - obj.signature = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntFromLeBytes obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.modulus = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::PedersenCommitment& lhs, const BlackBoxOp::PedersenCommitment& rhs) +inline bool operator==(const BlackBoxOp::BigIntToLeBytes& lhs, const BlackBoxOp::BigIntToLeBytes& rhs) { - if (!(lhs.inputs == rhs.inputs)) { - return false; - } - if (!(lhs.domain_separator == rhs.domain_separator)) { + if (!(lhs.input == rhs.input)) { return false; } if (!(lhs.output == rhs.output)) { @@ -3967,17 +4567,17 @@ inline bool operator==(const BlackBoxOp::PedersenCommitment& lhs, const BlackBox return true; } -inline std::vector BlackBoxOp::PedersenCommitment::bincodeSerialize() const +inline std::vector BlackBoxOp::BigIntToLeBytes::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDeserialize(std::vector input) +inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -3988,53 +4588,51 @@ inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::bincodeDes template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::PedersenCommitment& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::BigIntToLeBytes& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize( +Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::BigIntToLeBytes obj; + obj.input = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::PedersenHash& lhs, const BlackBoxOp::PedersenHash& rhs) +inline bool operator==(const BlackBoxOp::Poseidon2Permutation& lhs, const BlackBoxOp::Poseidon2Permutation& rhs) { - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { + if (!(lhs.output == rhs.output)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.len == rhs.len)) { return false; } return true; } -inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const +inline std::vector BlackBoxOp::Poseidon2Permutation::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4045,53 +4643,53 @@ inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::Poseidon2Permutation& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); + serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.len, serializer); } template <> template -Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize( +Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Poseidon2Permutation obj; + obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); + obj.len = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::FixedBaseScalarMul& lhs, const BlackBoxOp::FixedBaseScalarMul& rhs) +inline bool operator==(const BlackBoxOp::Sha256Compression& lhs, const BlackBoxOp::Sha256Compression& rhs) { - if (!(lhs.low == rhs.low)) { + if (!(lhs.input == rhs.input)) { return false; } - if (!(lhs.high == rhs.high)) { + if (!(lhs.hash_values == rhs.hash_values)) { return false; } - if (!(lhs.result == rhs.result)) { + if (!(lhs.output == rhs.output)) { return false; } return true; } -inline std::vector BlackBoxOp::FixedBaseScalarMul::bincodeSerialize() const +inline std::vector BlackBoxOp::Sha256Compression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDeserialize(std::vector input) +inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4102,59 +4700,47 @@ inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDes template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::FixedBaseScalarMul& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BlackBoxOp::Sha256Compression& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.low, serializer); - serde::Serializable::serialize(obj.high, serializer); - serde::Serializable::serialize(obj.result, serializer); + serde::Serializable::serialize(obj.input, serializer); + serde::Serializable::serialize(obj.hash_values, serializer); + serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize( +Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::FixedBaseScalarMul obj; - obj.low = serde::Deserializable::deserialize(deserializer); - obj.high = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); + Circuit::BlackBoxOp::Sha256Compression obj; + obj.input = serde::Deserializable::deserialize(deserializer); + obj.hash_values = serde::Deserializable::deserialize(deserializer); + obj.output = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd& lhs, const BlackBoxOp::EmbeddedCurveAdd& rhs) +inline bool operator==(const BlockId& lhs, const BlockId& rhs) { - if (!(lhs.input1_x == rhs.input1_x)) { - return false; - } - if (!(lhs.input1_y == rhs.input1_y)) { - return false; - } - if (!(lhs.input2_x == rhs.input2_x)) { - return false; - } - if (!(lhs.input2_y == rhs.input2_y)) { - return false; - } - if (!(lhs.result == rhs.result)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::EmbeddedCurveAdd::bincodeSerialize() const +inline std::vector BlockId::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeserialize(std::vector input) +inline BlockId BlockId::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4165,57 +4751,54 @@ inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeseria template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::EmbeddedCurveAdd& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BlockId& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.input1_x, serializer); - serde::Serializable::serialize(obj.input1_y, serializer); - serde::Serializable::serialize(obj.input2_x, serializer); - serde::Serializable::serialize(obj.input2_y, serializer); - serde::Serializable::serialize(obj.result, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BlockId serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::EmbeddedCurveAdd obj; - obj.input1_x = serde::Deserializable::deserialize(deserializer); - obj.input1_y = serde::Deserializable::deserialize(deserializer); - obj.input2_x = serde::Deserializable::deserialize(deserializer); - obj.input2_y = serde::Deserializable::deserialize(deserializer); - obj.result = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::BlockId obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::BigIntAdd& lhs, const BlackBoxOp::BigIntAdd& rhs) +inline bool operator==(const Brillig& lhs, const Brillig& rhs) { - if (!(lhs.lhs == rhs.lhs)) { + if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.outputs == rhs.outputs)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.bytecode == rhs.bytecode)) { + return false; + } + if (!(lhs.predicate == rhs.predicate)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntAdd::bincodeSerialize() const +inline std::vector Brillig::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntAdd BlackBoxOp::BigIntAdd::bincodeDeserialize(std::vector input) +inline Brillig Brillig::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4226,53 +4809,51 @@ inline BlackBoxOp::BigIntAdd BlackBoxOp::BigIntAdd::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::Brillig& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); + serde::Serializable::serialize(obj.bytecode, serializer); + serde::Serializable::serialize(obj.predicate, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntAdd obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::Brillig obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + obj.bytecode = serde::Deserializable::deserialize(deserializer); + obj.predicate = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } -namespace Circuit { - -inline bool operator==(const BlackBoxOp::BigIntNeg& lhs, const BlackBoxOp::BigIntNeg& rhs) -{ - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { - return false; - } - if (!(lhs.output == rhs.output)) { +namespace Circuit { + +inline bool operator==(const BrilligInputs& lhs, const BrilligInputs& rhs) +{ + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntNeg::bincodeSerialize() const +inline std::vector BrilligInputs::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntNeg BlackBoxOp::BigIntNeg::bincodeDeserialize(std::vector input) +inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4283,53 +4864,45 @@ inline BlackBoxOp::BigIntNeg BlackBoxOp::BigIntNeg::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntNeg& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligInputs& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntNeg serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntNeg obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::BrilligInputs obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::BigIntMul& lhs, const BlackBoxOp::BigIntMul& rhs) +inline bool operator==(const BrilligInputs::Single& lhs, const BrilligInputs::Single& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { - return false; - } - if (!(lhs.output == rhs.output)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntMul::bincodeSerialize() const +inline std::vector BrilligInputs::Single::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vector input) +inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4340,53 +4913,43 @@ inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul& obj, +void serde::Serializable::serialize(const Circuit::BrilligInputs::Single& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize( +Circuit::BrilligInputs::Single serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntMul obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligInputs::Single obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::BigIntDiv& lhs, const BlackBoxOp::BigIntDiv& rhs) +inline bool operator==(const BrilligInputs::Array& lhs, const BrilligInputs::Array& rhs) { - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { - return false; - } - if (!(lhs.output == rhs.output)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntDiv::bincodeSerialize() const +inline std::vector BrilligInputs::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vector input) +inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4397,53 +4960,43 @@ inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligInputs::Array& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize( +Circuit::BrilligInputs::Array serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntDiv obj; - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligInputs::Array obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::BigIntFromLeBytes& lhs, const BlackBoxOp::BigIntFromLeBytes& rhs) +inline bool operator==(const BrilligInputs::MemoryArray& lhs, const BrilligInputs::MemoryArray& rhs) { - if (!(lhs.inputs == rhs.inputs)) { - return false; - } - if (!(lhs.modulus == rhs.modulus)) { - return false; - } - if (!(lhs.output == rhs.output)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntFromLeBytes::bincodeSerialize() const +inline std::vector BrilligInputs::MemoryArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeserialize(std::vector input) +inline BrilligInputs::MemoryArray BrilligInputs::MemoryArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4454,50 +5007,43 @@ inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeser template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::BigIntFromLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.modulus, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize( +Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntFromLeBytes obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.modulus = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligInputs::MemoryArray obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::BigIntToLeBytes& lhs, const BlackBoxOp::BigIntToLeBytes& rhs) +inline bool operator==(const BrilligOpcode& lhs, const BrilligOpcode& rhs) { - if (!(lhs.input == rhs.input)) { - return false; - } - if (!(lhs.output == rhs.output)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BlackBoxOp::BigIntToLeBytes::bincodeSerialize() const +inline std::vector BrilligOpcode::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeserialize(std::vector input) +inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4508,51 +5054,54 @@ inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::BigIntToLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.output, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntToLeBytes obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::BrilligOpcode obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Poseidon2Permutation& lhs, const BlackBoxOp::Poseidon2Permutation& rhs) +inline bool operator==(const BrilligOpcode::BinaryFieldOp& lhs, const BrilligOpcode::BinaryFieldOp& rhs) { - if (!(lhs.message == rhs.message)) { + if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.op == rhs.op)) { return false; } - if (!(lhs.len == rhs.len)) { + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { return false; } return true; } -inline std::vector BlackBoxOp::Poseidon2Permutation::bincodeSerialize() const +inline std::vector BrilligOpcode::BinaryFieldOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincodeDeserialize(std::vector input) +inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4563,53 +5112,61 @@ inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincod template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::Poseidon2Permutation& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BrilligOpcode::BinaryFieldOp& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); - serde::Serializable::serialize(obj.len, serializer); + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.op, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); } template <> template -Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize( +Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Poseidon2Permutation obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - obj.len = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::BinaryFieldOp obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.op = serde::Deserializable::deserialize(deserializer); + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlackBoxOp::Sha256Compression& lhs, const BlackBoxOp::Sha256Compression& rhs) +inline bool operator==(const BrilligOpcode::BinaryIntOp& lhs, const BrilligOpcode::BinaryIntOp& rhs) { - if (!(lhs.input == rhs.input)) { + if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.hash_values == rhs.hash_values)) { + if (!(lhs.op == rhs.op)) { return false; } - if (!(lhs.output == rhs.output)) { + if (!(lhs.bit_size == rhs.bit_size)) { + return false; + } + if (!(lhs.lhs == rhs.lhs)) { + return false; + } + if (!(lhs.rhs == rhs.rhs)) { return false; } return true; } -inline std::vector BlackBoxOp::Sha256Compression::bincodeSerialize() const +inline std::vector BrilligOpcode::BinaryIntOp::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeserialize(std::vector input) +inline BrilligOpcode::BinaryIntOp BrilligOpcode::BinaryIntOp::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4620,47 +5177,57 @@ inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeser template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::Sha256Compression& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.input, serializer); - serde::Serializable::serialize(obj.hash_values, serializer); - serde::Serializable::serialize(obj.output, serializer); + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.op, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); + serde::Serializable::serialize(obj.lhs, serializer); + serde::Serializable::serialize(obj.rhs, serializer); } template <> template -Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize( +Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Sha256Compression obj; - obj.input = serde::Deserializable::deserialize(deserializer); - obj.hash_values = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::BinaryIntOp obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.op = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); + obj.lhs = serde::Deserializable::deserialize(deserializer); + obj.rhs = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BlockId& lhs, const BlockId& rhs) +inline bool operator==(const BrilligOpcode::Cast& lhs, const BrilligOpcode::Cast& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.destination == rhs.destination)) { + return false; + } + if (!(lhs.source == rhs.source)) { + return false; + } + if (!(lhs.bit_size == rhs.bit_size)) { return false; } return true; } -inline std::vector BlockId::bincodeSerialize() const +inline std::vector BrilligOpcode::Cast::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BlockId BlockId::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Cast BrilligOpcode::Cast::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4671,54 +5238,50 @@ inline BlockId BlockId::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::BlockId& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Cast& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); } template <> template -Circuit::BlockId serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BrilligOpcode::Cast serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BlockId obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BrilligOpcode::Cast obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const Brillig& lhs, const Brillig& rhs) +inline bool operator==(const BrilligOpcode::JumpIfNot& lhs, const BrilligOpcode::JumpIfNot& rhs) { - if (!(lhs.inputs == rhs.inputs)) { - return false; - } - if (!(lhs.outputs == rhs.outputs)) { - return false; - } - if (!(lhs.bytecode == rhs.bytecode)) { + if (!(lhs.condition == rhs.condition)) { return false; } - if (!(lhs.predicate == rhs.predicate)) { + if (!(lhs.location == rhs.location)) { return false; } return true; } -inline std::vector Brillig::bincodeSerialize() const +inline std::vector BrilligOpcode::JumpIfNot::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Brillig Brillig::bincodeDeserialize(std::vector input) +inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4729,51 +5292,48 @@ inline Brillig Brillig::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::Brillig& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.outputs, serializer); - serde::Serializable::serialize(obj.bytecode, serializer); - serde::Serializable::serialize(obj.predicate, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.condition, serializer); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::Brillig obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - obj.bytecode = serde::Deserializable::deserialize(deserializer); - obj.predicate = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BrilligOpcode::JumpIfNot obj; + obj.condition = serde::Deserializable::deserialize(deserializer); + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligInputs& lhs, const BrilligInputs& rhs) +inline bool operator==(const BrilligOpcode::JumpIf& lhs, const BrilligOpcode::JumpIf& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.condition == rhs.condition)) { + return false; + } + if (!(lhs.location == rhs.location)) { return false; } return true; } -inline std::vector BrilligInputs::bincodeSerialize() const +inline std::vector BrilligOpcode::JumpIf::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector input) +inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4784,45 +5344,45 @@ inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector inpu template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.condition, serializer); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BrilligInputs obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BrilligOpcode::JumpIf obj; + obj.condition = serde::Deserializable::deserialize(deserializer); + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligInputs::Single& lhs, const BrilligInputs::Single& rhs) +inline bool operator==(const BrilligOpcode::Jump& lhs, const BrilligOpcode::Jump& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.location == rhs.location)) { return false; } return true; } -inline std::vector BrilligInputs::Single::bincodeSerialize() const +inline std::vector BrilligOpcode::Jump::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4833,43 +5393,49 @@ inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Single& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligInputs::Single serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligInputs::Single obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::Jump obj; + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligInputs::Array& lhs, const BrilligInputs::Array& rhs) +inline bool operator==(const BrilligOpcode::CalldataCopy& lhs, const BrilligOpcode::CalldataCopy& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.destination_address == rhs.destination_address)) { + return false; + } + if (!(lhs.size == rhs.size)) { + return false; + } + if (!(lhs.offset == rhs.offset)) { return false; } return true; } -inline std::vector BrilligInputs::Array::bincodeSerialize() const +inline std::vector BrilligOpcode::CalldataCopy::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) +inline BrilligOpcode::CalldataCopy BrilligOpcode::CalldataCopy::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4880,43 +5446,47 @@ inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Array& obj, - Serializer& serializer) +void serde::Serializable::serialize( + const Circuit::BrilligOpcode::CalldataCopy& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.destination_address, serializer); + serde::Serializable::serialize(obj.size, serializer); + serde::Serializable::serialize(obj.offset, serializer); } template <> template -Circuit::BrilligInputs::Array serde::Deserializable::deserialize( +Circuit::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligInputs::Array obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::CalldataCopy obj; + obj.destination_address = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + obj.offset = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode& lhs, const BrilligOpcode& rhs) +inline bool operator==(const BrilligOpcode::Call& lhs, const BrilligOpcode::Call& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.location == rhs.location)) { return false; } return true; } -inline std::vector BrilligOpcode::bincodeSerialize() const +inline std::vector BrilligOpcode::Call::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4927,54 +5497,49 @@ inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector inpu template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BrilligOpcode::Call serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::BrilligOpcode obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::BrilligOpcode::Call obj; + obj.location = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::BinaryFieldOp& lhs, const BrilligOpcode::BinaryFieldOp& rhs) +inline bool operator==(const BrilligOpcode::Const& lhs, const BrilligOpcode::Const& rhs) { if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.op == rhs.op)) { - return false; - } - if (!(lhs.lhs == rhs.lhs)) { + if (!(lhs.bit_size == rhs.bit_size)) { return false; } - if (!(lhs.rhs == rhs.rhs)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BrilligOpcode::BinaryFieldOp::bincodeSerialize() const +inline std::vector BrilligOpcode::Const::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -4985,61 +5550,44 @@ inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeseria template <> template -void serde::Serializable::serialize( - const Circuit::BrilligOpcode::BinaryFieldOp& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const& obj, + Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.op, serializer); - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Const serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::BinaryFieldOp obj; + Circuit::BrilligOpcode::Const obj; obj.destination = serde::Deserializable::deserialize(deserializer); - obj.op = serde::Deserializable::deserialize(deserializer); - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::BinaryIntOp& lhs, const BrilligOpcode::BinaryIntOp& rhs) +inline bool operator==(const BrilligOpcode::Return& lhs, const BrilligOpcode::Return& rhs) { - if (!(lhs.destination == rhs.destination)) { - return false; - } - if (!(lhs.op == rhs.op)) { - return false; - } - if (!(lhs.bit_size == rhs.bit_size)) { - return false; - } - if (!(lhs.lhs == rhs.lhs)) { - return false; - } - if (!(lhs.rhs == rhs.rhs)) { - return false; - } return true; } -inline std::vector BrilligOpcode::BinaryIntOp::bincodeSerialize() const +inline std::vector BrilligOpcode::Return::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::BinaryIntOp BrilligOpcode::BinaryIntOp::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5050,54 +5598,52 @@ inline BrilligOpcode::BinaryIntOp BrilligOpcode::BinaryIntOp::bincodeDeserialize template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp& obj, - Serializer& serializer) -{ - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.op, serializer); - serde::Serializable::serialize(obj.bit_size, serializer); - serde::Serializable::serialize(obj.lhs, serializer); - serde::Serializable::serialize(obj.rhs, serializer); -} +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return& obj, + Serializer& serializer) +{} template <> template -Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize( - Deserializer& deserializer) -{ - Circuit::BrilligOpcode::BinaryIntOp obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.op = serde::Deserializable::deserialize(deserializer); - obj.bit_size = serde::Deserializable::deserialize(deserializer); - obj.lhs = serde::Deserializable::deserialize(deserializer); - obj.rhs = serde::Deserializable::deserialize(deserializer); +Circuit::BrilligOpcode::Return serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BrilligOpcode::Return obj; return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::JumpIfNot& lhs, const BrilligOpcode::JumpIfNot& rhs) +inline bool operator==(const BrilligOpcode::ForeignCall& lhs, const BrilligOpcode::ForeignCall& rhs) { - if (!(lhs.condition == rhs.condition)) { + if (!(lhs.function == rhs.function)) { return false; } - if (!(lhs.location == rhs.location)) { + if (!(lhs.destinations == rhs.destinations)) { + return false; + } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { + return false; + } + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } -inline std::vector BrilligOpcode::JumpIfNot::bincodeSerialize() const +inline std::vector BrilligOpcode::ForeignCall::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std::vector input) +inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5108,48 +5654,55 @@ inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.condition, serializer); - serde::Serializable::serialize(obj.location, serializer); + serde::Serializable::serialize(obj.function, serializer); + serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> template -Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize( +Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::JumpIfNot obj; - obj.condition = serde::Deserializable::deserialize(deserializer); - obj.location = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::ForeignCall obj; + obj.function = serde::Deserializable::deserialize(deserializer); + obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = + serde::Deserializable::deserialize(deserializer); + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::JumpIf& lhs, const BrilligOpcode::JumpIf& rhs) +inline bool operator==(const BrilligOpcode::Mov& lhs, const BrilligOpcode::Mov& rhs) { - if (!(lhs.condition == rhs.condition)) { + if (!(lhs.destination == rhs.destination)) { return false; } - if (!(lhs.location == rhs.location)) { + if (!(lhs.source == rhs.source)) { return false; } return true; } -inline std::vector BrilligOpcode::JumpIf::bincodeSerialize() const +inline std::vector BrilligOpcode::Mov::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Mov BrilligOpcode::Mov::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5160,45 +5713,47 @@ inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.condition, serializer); - serde::Serializable::serialize(obj.location, serializer); + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOpcode::JumpIf obj; - obj.condition = serde::Deserializable::deserialize(deserializer); - obj.location = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::Mov obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Jump& lhs, const BrilligOpcode::Jump& rhs) +inline bool operator==(const BrilligOpcode::Load& lhs, const BrilligOpcode::Load& rhs) { - if (!(lhs.location == rhs.location)) { + if (!(lhs.destination == rhs.destination)) { + return false; + } + if (!(lhs.source_pointer == rhs.source_pointer)) { return false; } return true; } -inline std::vector BrilligOpcode::Jump::bincodeSerialize() const +inline std::vector BrilligOpcode::Load::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5209,49 +5764,48 @@ inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump& obj, +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.location, serializer); + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source_pointer, serializer); } template <> template -Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Load serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Jump obj; - obj.location = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::Load obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source_pointer = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::CalldataCopy& lhs, const BrilligOpcode::CalldataCopy& rhs) +inline bool operator==(const BrilligOpcode::Store& lhs, const BrilligOpcode::Store& rhs) { - if (!(lhs.destination_address == rhs.destination_address)) { - return false; - } - if (!(lhs.size == rhs.size)) { + if (!(lhs.destination_pointer == rhs.destination_pointer)) { return false; } - if (!(lhs.offset == rhs.offset)) { + if (!(lhs.source == rhs.source)) { return false; } return true; } -inline std::vector BrilligOpcode::CalldataCopy::bincodeSerialize() const +inline std::vector BrilligOpcode::Store::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::CalldataCopy BrilligOpcode::CalldataCopy::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5262,47 +5816,45 @@ inline BrilligOpcode::CalldataCopy BrilligOpcode::CalldataCopy::bincodeDeseriali template <> template -void serde::Serializable::serialize( - const Circuit::BrilligOpcode::CalldataCopy& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.destination_address, serializer); - serde::Serializable::serialize(obj.size, serializer); - serde::Serializable::serialize(obj.offset, serializer); + serde::Serializable::serialize(obj.destination_pointer, serializer); + serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Store serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::CalldataCopy obj; - obj.destination_address = serde::Deserializable::deserialize(deserializer); - obj.size = serde::Deserializable::deserialize(deserializer); - obj.offset = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::Store obj; + obj.destination_pointer = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Call& lhs, const BrilligOpcode::Call& rhs) +inline bool operator==(const BrilligOpcode::BlackBox& lhs, const BrilligOpcode::BlackBox& rhs) { - if (!(lhs.location == rhs.location)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BrilligOpcode::Call::bincodeSerialize() const +inline std::vector BrilligOpcode::BlackBox::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector input) +inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5313,46 +5865,40 @@ inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.location, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::Call serde::Deserializable::deserialize( +Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Call obj; - obj.location = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::BlackBox obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Const& lhs, const BrilligOpcode::Const& rhs) +inline bool operator==(const BrilligOpcode::Trap& lhs, const BrilligOpcode::Trap& rhs) { - if (!(lhs.destination == rhs.destination)) { - return false; - } - if (!(lhs.value == rhs.value)) { - return false; - } return true; } -inline std::vector BrilligOpcode::Const::bincodeSerialize() const +inline std::vector BrilligOpcode::Trap::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5363,42 +5909,43 @@ inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const& obj, - Serializer& serializer) -{ - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.value, serializer); -} +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap& obj, + Serializer& serializer) +{} template <> template -Circuit::BrilligOpcode::Const serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Const obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOpcode::Trap obj; return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Return& lhs, const BrilligOpcode::Return& rhs) +inline bool operator==(const BrilligOpcode::Stop& lhs, const BrilligOpcode::Stop& rhs) { + if (!(lhs.return_data_offset == rhs.return_data_offset)) { + return false; + } + if (!(lhs.return_data_size == rhs.return_data_size)) { + return false; + } return true; } -inline std::vector BrilligOpcode::Return::bincodeSerialize() const +inline std::vector BrilligOpcode::Stop::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vector input) +inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5409,46 +5956,45 @@ inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.return_data_offset, serializer); + serde::Serializable::serialize(obj.return_data_size, serializer); +} template <> template -Circuit::BrilligOpcode::Return serde::Deserializable::deserialize( +Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Return obj; + Circuit::BrilligOpcode::Stop obj; + obj.return_data_offset = serde::Deserializable::deserialize(deserializer); + obj.return_data_size = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::ForeignCall& lhs, const BrilligOpcode::ForeignCall& rhs) +inline bool operator==(const BrilligOutputs& lhs, const BrilligOutputs& rhs) { - if (!(lhs.function == rhs.function)) { - return false; - } - if (!(lhs.destinations == rhs.destinations)) { - return false; - } - if (!(lhs.inputs == rhs.inputs)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BrilligOpcode::ForeignCall::bincodeSerialize() const +inline std::vector BrilligOutputs::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize(std::vector input) +inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5459,50 +6005,45 @@ inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOutputs& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.function, serializer); - serde::Serializable::serialize(obj.destinations, serializer); - serde::Serializable::serialize(obj.inputs, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOpcode::ForeignCall obj; - obj.function = serde::Deserializable::deserialize(deserializer); - obj.destinations = serde::Deserializable::deserialize(deserializer); - obj.inputs = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::BrilligOutputs obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Mov& lhs, const BrilligOpcode::Mov& rhs) +inline bool operator==(const BrilligOutputs::Simple& lhs, const BrilligOutputs::Simple& rhs) { - if (!(lhs.destination == rhs.destination)) { - return false; - } - if (!(lhs.source == rhs.source)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BrilligOpcode::Mov::bincodeSerialize() const +inline std::vector BrilligOutputs::Simple::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Mov BrilligOpcode::Mov::bincodeDeserialize(std::vector input) +inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5513,47 +6054,43 @@ inline BrilligOpcode::Mov BrilligOpcode::Mov::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.source, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize( + Deserializer& deserializer) { - Circuit::BrilligOpcode::Mov obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.source = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOutputs::Simple obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Load& lhs, const BrilligOpcode::Load& rhs) +inline bool operator==(const BrilligOutputs::Array& lhs, const BrilligOutputs::Array& rhs) { - if (!(lhs.destination == rhs.destination)) { - return false; - } - if (!(lhs.source_pointer == rhs.source_pointer)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector BrilligOpcode::Load::bincodeSerialize() const +inline std::vector BrilligOutputs::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector input) +inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5564,48 +6101,64 @@ inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.destination, serializer); - serde::Serializable::serialize(obj.source_pointer, serializer); + serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::Load serde::Deserializable::deserialize( +Circuit::BrilligOutputs::Array serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Load obj; - obj.destination = serde::Deserializable::deserialize(deserializer); - obj.source_pointer = serde::Deserializable::deserialize(deserializer); + Circuit::BrilligOutputs::Array obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Store& lhs, const BrilligOpcode::Store& rhs) +inline bool operator==(const Circuit& lhs, const Circuit& rhs) { - if (!(lhs.destination_pointer == rhs.destination_pointer)) { + if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } - if (!(lhs.source == rhs.source)) { + if (!(lhs.opcodes == rhs.opcodes)) { + return false; + } + if (!(lhs.expression_width == rhs.expression_width)) { + return false; + } + if (!(lhs.private_parameters == rhs.private_parameters)) { + return false; + } + if (!(lhs.public_parameters == rhs.public_parameters)) { + return false; + } + if (!(lhs.return_values == rhs.return_values)) { + return false; + } + if (!(lhs.assert_messages == rhs.assert_messages)) { + return false; + } + if (!(lhs.recursive == rhs.recursive)) { return false; } return true; } -inline std::vector BrilligOpcode::Store::bincodeSerialize() const +inline std::vector Circuit::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector input) +inline Circuit Circuit::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5616,27 +6169,41 @@ inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::Circuit& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.destination_pointer, serializer); - serde::Serializable::serialize(obj.source, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.current_witness_index, serializer); + serde::Serializable::serialize(obj.opcodes, serializer); + serde::Serializable::serialize(obj.expression_width, serializer); + serde::Serializable::serialize(obj.private_parameters, serializer); + serde::Serializable::serialize(obj.public_parameters, serializer); + serde::Serializable::serialize(obj.return_values, serializer); + serde::Serializable::serialize(obj.assert_messages, serializer); + serde::Serializable::serialize(obj.recursive, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::Store serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::Circuit serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOpcode::Store obj; - obj.destination_pointer = serde::Deserializable::deserialize(deserializer); - obj.source = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::Circuit obj; + obj.current_witness_index = serde::Deserializable::deserialize(deserializer); + obj.opcodes = serde::Deserializable::deserialize(deserializer); + obj.expression_width = serde::Deserializable::deserialize(deserializer); + obj.private_parameters = serde::Deserializable::deserialize(deserializer); + obj.public_parameters = serde::Deserializable::deserialize(deserializer); + obj.return_values = serde::Deserializable::deserialize(deserializer); + obj.assert_messages = serde::Deserializable::deserialize(deserializer); + obj.recursive = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::BlackBox& lhs, const BrilligOpcode::BlackBox& rhs) +inline bool operator==(const Directive& lhs, const Directive& rhs) { if (!(lhs.value == rhs.value)) { return false; @@ -5644,17 +6211,17 @@ inline bool operator==(const BrilligOpcode::BlackBox& lhs, const BrilligOpcode:: return true; } -inline std::vector BrilligOpcode::BlackBox::bincodeSerialize() const +inline std::vector Directive::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std::vector input) +inline Directive Directive::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5665,40 +6232,51 @@ inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std:: template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::Directive& obj, Serializer& serializer) { + serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::Directive serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOpcode::BlackBox obj; + deserializer.increase_container_depth(); + Circuit::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Trap& lhs, const BrilligOpcode::Trap& rhs) +inline bool operator==(const Directive::ToLeRadix& lhs, const Directive::ToLeRadix& rhs) { + if (!(lhs.a == rhs.a)) { + return false; + } + if (!(lhs.b == rhs.b)) { + return false; + } + if (!(lhs.radix == rhs.radix)) { + return false; + } return true; } -inline std::vector BrilligOpcode::Trap::bincodeSerialize() const +inline std::vector Directive::ToLeRadix::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector input) +inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5709,43 +6287,56 @@ inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap& obj, - Serializer& serializer) -{} +void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.a, serializer); + serde::Serializable::serialize(obj.b, serializer); + serde::Serializable::serialize(obj.radix, serializer); +} template <> template -Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize( +Circuit::Directive::ToLeRadix serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Trap obj; + Circuit::Directive::ToLeRadix obj; + obj.a = serde::Deserializable::deserialize(deserializer); + obj.b = serde::Deserializable::deserialize(deserializer); + obj.radix = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOpcode::Stop& lhs, const BrilligOpcode::Stop& rhs) +inline bool operator==(const Directive::PermutationSort& lhs, const Directive::PermutationSort& rhs) { - if (!(lhs.return_data_offset == rhs.return_data_offset)) { + if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.return_data_size == rhs.return_data_size)) { + if (!(lhs.tuple == rhs.tuple)) { + return false; + } + if (!(lhs.bits == rhs.bits)) { + return false; + } + if (!(lhs.sort_by == rhs.sort_by)) { return false; } return true; } -inline std::vector BrilligOpcode::Stop::bincodeSerialize() const +inline std::vector Directive::PermutationSort::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector input) +inline Directive::PermutationSort Directive::PermutationSort::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5756,45 +6347,55 @@ inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::Directive::PermutationSort& obj, + Serializer& serializer) { - serde::Serializable::serialize(obj.return_data_offset, serializer); - serde::Serializable::serialize(obj.return_data_size, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.tuple, serializer); + serde::Serializable::serialize(obj.bits, serializer); + serde::Serializable::serialize(obj.sort_by, serializer); } template <> template -Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize( +Circuit::Directive::PermutationSort serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Stop obj; - obj.return_data_offset = serde::Deserializable::deserialize(deserializer); - obj.return_data_size = serde::Deserializable::deserialize(deserializer); + Circuit::Directive::PermutationSort obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.tuple = serde::Deserializable::deserialize(deserializer); + obj.bits = serde::Deserializable::deserialize(deserializer); + obj.sort_by = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const BrilligOutputs& lhs, const BrilligOutputs& rhs) +inline bool operator==(const Expression& lhs, const Expression& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.mul_terms == rhs.mul_terms)) { + return false; + } + if (!(lhs.linear_combinations == rhs.linear_combinations)) { + return false; + } + if (!(lhs.q_c == rhs.q_c)) { return false; } return true; } -inline std::vector BrilligOutputs::bincodeSerialize() const +inline std::vector Expression::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector input) +inline Expression Expression::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5805,27 +6406,31 @@ inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector in template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::Expression& obj, Serializer& serializer) { serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.mul_terms, serializer); + serde::Serializable::serialize(obj.linear_combinations, serializer); + serde::Serializable::serialize(obj.q_c, serializer); serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::Expression serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOutputs obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::Expression obj; + obj.mul_terms = serde::Deserializable::deserialize(deserializer); + obj.linear_combinations = serde::Deserializable::deserialize(deserializer); + obj.q_c = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BrilligOutputs::Simple& lhs, const BrilligOutputs::Simple& rhs) +inline bool operator==(const ExpressionWidth& lhs, const ExpressionWidth& rhs) { if (!(lhs.value == rhs.value)) { return false; @@ -5833,17 +6438,17 @@ inline bool operator==(const BrilligOutputs::Simple& lhs, const BrilligOutputs:: return true; } -inline std::vector BrilligOutputs::Simple::bincodeSerialize() const +inline std::vector ExpressionWidth::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::vector input) +inline ExpressionWidth ExpressionWidth::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5854,43 +6459,43 @@ inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::ve template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::ExpressionWidth& obj, + Serializer& serializer) { + serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOutputs::Simple obj; + deserializer.increase_container_depth(); + Circuit::ExpressionWidth obj; obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const BrilligOutputs::Array& lhs, const BrilligOutputs::Array& rhs) +inline bool operator==(const ExpressionWidth::Unbounded& lhs, const ExpressionWidth::Unbounded& rhs) { - if (!(lhs.value == rhs.value)) { - return false; - } return true; } -inline std::vector BrilligOutputs::Array::bincodeSerialize() const +inline std::vector ExpressionWidth::Unbounded::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vector input) +inline ExpressionWidth::Unbounded ExpressionWidth::Unbounded::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5901,61 +6506,40 @@ inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vect template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array& obj, - Serializer& serializer) -{ - serde::Serializable::serialize(obj.value, serializer); -} +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded& obj, + Serializer& serializer) +{} template <> template -Circuit::BrilligOutputs::Array serde::Deserializable::deserialize( +Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOutputs::Array obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::ExpressionWidth::Unbounded obj; return obj; } namespace Circuit { -inline bool operator==(const Circuit& lhs, const Circuit& rhs) +inline bool operator==(const ExpressionWidth::Bounded& lhs, const ExpressionWidth::Bounded& rhs) { - if (!(lhs.current_witness_index == rhs.current_witness_index)) { - return false; - } - if (!(lhs.opcodes == rhs.opcodes)) { - return false; - } - if (!(lhs.private_parameters == rhs.private_parameters)) { - return false; - } - if (!(lhs.public_parameters == rhs.public_parameters)) { - return false; - } - if (!(lhs.return_values == rhs.return_values)) { - return false; - } - if (!(lhs.assert_messages == rhs.assert_messages)) { - return false; - } - if (!(lhs.recursive == rhs.recursive)) { + if (!(lhs.width == rhs.width)) { return false; } return true; } -inline std::vector Circuit::bincodeSerialize() const +inline std::vector ExpressionWidth::Bounded::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Circuit Circuit::bincodeDeserialize(std::vector input) +inline ExpressionWidth::Bounded ExpressionWidth::Bounded::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -5966,57 +6550,46 @@ inline Circuit Circuit::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::Circuit& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.current_witness_index, serializer); - serde::Serializable::serialize(obj.opcodes, serializer); - serde::Serializable::serialize(obj.private_parameters, serializer); - serde::Serializable::serialize(obj.public_parameters, serializer); - serde::Serializable::serialize(obj.return_values, serializer); - serde::Serializable::serialize(obj.assert_messages, serializer); - serde::Serializable::serialize(obj.recursive, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.width, serializer); } template <> template -Circuit::Circuit serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::Circuit obj; - obj.current_witness_index = serde::Deserializable::deserialize(deserializer); - obj.opcodes = serde::Deserializable::deserialize(deserializer); - obj.private_parameters = serde::Deserializable::deserialize(deserializer); - obj.public_parameters = serde::Deserializable::deserialize(deserializer); - obj.return_values = serde::Deserializable::deserialize(deserializer); - obj.assert_messages = serde::Deserializable::deserialize(deserializer); - obj.recursive = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::ExpressionWidth::Bounded obj; + obj.width = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const Directive& lhs, const Directive& rhs) +inline bool operator==(const FunctionInput& lhs, const FunctionInput& rhs) { - if (!(lhs.value == rhs.value)) { + if (!(lhs.witness == rhs.witness)) { + return false; + } + if (!(lhs.num_bits == rhs.num_bits)) { return false; } return true; } -inline std::vector Directive::bincodeSerialize() const +inline std::vector FunctionInput::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Directive Directive::bincodeDeserialize(std::vector input) +inline FunctionInput FunctionInput::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6027,51 +6600,50 @@ inline Directive Directive::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::Directive& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::FunctionInput& obj, Serializer& serializer) { serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); + serde::Serializable::serialize(obj.witness, serializer); + serde::Serializable::serialize(obj.num_bits, serializer); serializer.decrease_container_depth(); } template <> template -Circuit::Directive serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Directive obj; - obj.value = serde::Deserializable::deserialize(deserializer); + Circuit::FunctionInput obj; + obj.witness = serde::Deserializable::deserialize(deserializer); + obj.num_bits = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const Directive::ToLeRadix& lhs, const Directive::ToLeRadix& rhs) +inline bool operator==(const HeapArray& lhs, const HeapArray& rhs) { - if (!(lhs.a == rhs.a)) { - return false; - } - if (!(lhs.b == rhs.b)) { + if (!(lhs.pointer == rhs.pointer)) { return false; } - if (!(lhs.radix == rhs.radix)) { + if (!(lhs.size == rhs.size)) { return false; } return true; } -inline std::vector Directive::ToLeRadix::bincodeSerialize() const +inline std::vector HeapArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector input) +inline HeapArray HeapArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6082,56 +6654,47 @@ inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector template <> template -void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::HeapArray& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.a, serializer); - serde::Serializable::serialize(obj.b, serializer); - serde::Serializable::serialize(obj.radix, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.pointer, serializer); + serde::Serializable::serialize(obj.size, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::Directive::ToLeRadix serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::HeapArray serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Directive::ToLeRadix obj; - obj.a = serde::Deserializable::deserialize(deserializer); - obj.b = serde::Deserializable::deserialize(deserializer); - obj.radix = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::HeapArray obj; + obj.pointer = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const Directive::PermutationSort& lhs, const Directive::PermutationSort& rhs) +inline bool operator==(const HeapValueType& lhs, const HeapValueType& rhs) { - if (!(lhs.inputs == rhs.inputs)) { - return false; - } - if (!(lhs.tuple == rhs.tuple)) { - return false; - } - if (!(lhs.bits == rhs.bits)) { - return false; - } - if (!(lhs.sort_by == rhs.sort_by)) { + if (!(lhs.value == rhs.value)) { return false; } return true; } -inline std::vector Directive::PermutationSort::bincodeSerialize() const +inline std::vector HeapValueType::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Directive::PermutationSort Directive::PermutationSort::bincodeDeserialize(std::vector input) +inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6142,55 +6705,42 @@ inline Directive::PermutationSort Directive::PermutationSort::bincodeDeserialize template <> template -void serde::Serializable::serialize(const Circuit::Directive::PermutationSort& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::HeapValueType& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.tuple, serializer); - serde::Serializable::serialize(obj.bits, serializer); - serde::Serializable::serialize(obj.sort_by, serializer); + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Circuit::Directive::PermutationSort serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Directive::PermutationSort obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.tuple = serde::Deserializable::deserialize(deserializer); - obj.bits = serde::Deserializable::deserialize(deserializer); - obj.sort_by = serde::Deserializable::deserialize(deserializer); + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Circuit { -inline bool operator==(const Expression& lhs, const Expression& rhs) +inline bool operator==(const HeapValueType::Simple& lhs, const HeapValueType::Simple& rhs) { - if (!(lhs.mul_terms == rhs.mul_terms)) { - return false; - } - if (!(lhs.linear_combinations == rhs.linear_combinations)) { - return false; - } - if (!(lhs.q_c == rhs.q_c)) { - return false; - } return true; } -inline std::vector Expression::bincodeSerialize() const +inline std::vector HeapValueType::Simple::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline Expression Expression::bincodeDeserialize(std::vector input) +inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6201,52 +6751,43 @@ inline Expression Expression::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::Expression& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.mul_terms, serializer); - serde::Serializable::serialize(obj.linear_combinations, serializer); - serde::Serializable::serialize(obj.q_c, serializer); - serializer.decrease_container_depth(); -} +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple& obj, + Serializer& serializer) +{} template <> template -Circuit::Expression serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::HeapValueType::Simple serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::Expression obj; - obj.mul_terms = serde::Deserializable::deserialize(deserializer); - obj.linear_combinations = serde::Deserializable::deserialize(deserializer); - obj.q_c = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::HeapValueType::Simple obj; return obj; } namespace Circuit { -inline bool operator==(const FunctionInput& lhs, const FunctionInput& rhs) +inline bool operator==(const HeapValueType::Array& lhs, const HeapValueType::Array& rhs) { - if (!(lhs.witness == rhs.witness)) { + if (!(lhs.value_types == rhs.value_types)) { return false; } - if (!(lhs.num_bits == rhs.num_bits)) { + if (!(lhs.size == rhs.size)) { return false; } return true; } -inline std::vector FunctionInput::bincodeSerialize() const +inline std::vector HeapValueType::Array::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline FunctionInput FunctionInput::bincodeDeserialize(std::vector input) +inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6257,50 +6798,45 @@ inline FunctionInput FunctionInput::bincodeDeserialize(std::vector inpu template <> template -void serde::Serializable::serialize(const Circuit::FunctionInput& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::HeapValueType::Array& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.witness, serializer); - serde::Serializable::serialize(obj.num_bits, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); } template <> template -Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::HeapValueType::Array serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::FunctionInput obj; - obj.witness = serde::Deserializable::deserialize(deserializer); - obj.num_bits = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); return obj; } namespace Circuit { -inline bool operator==(const HeapArray& lhs, const HeapArray& rhs) +inline bool operator==(const HeapValueType::Vector& lhs, const HeapValueType::Vector& rhs) { - if (!(lhs.pointer == rhs.pointer)) { - return false; - } - if (!(lhs.size == rhs.size)) { + if (!(lhs.value_types == rhs.value_types)) { return false; } return true; } -inline std::vector HeapArray::bincodeSerialize() const +inline std::vector HeapValueType::Vector::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline HeapArray HeapArray::bincodeDeserialize(std::vector input) +inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -6311,23 +6847,19 @@ inline HeapArray HeapArray::bincodeDeserialize(std::vector input) template <> template -void serde::Serializable::serialize(const Circuit::HeapArray& obj, Serializer& serializer) +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector& obj, + Serializer& serializer) { - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.pointer, serializer); - serde::Serializable::serialize(obj.size, serializer); - serializer.decrease_container_depth(); + serde::Serializable::serialize(obj.value_types, serializer); } template <> template -Circuit::HeapArray serde::Deserializable::deserialize(Deserializer& deserializer) +Circuit::HeapValueType::Vector serde::Deserializable::deserialize( + Deserializer& deserializer) { - deserializer.increase_container_depth(); - Circuit::HeapArray obj; - obj.pointer = serde::Deserializable::deserialize(deserializer); - obj.size = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); return obj; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp index a40c775ab4d..18279607dba 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp @@ -218,56 +218,49 @@ abstract contract BaseUltraVerifier { uint256 internal constant PAIRING_RHS_X_LOC = 0x3220; uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240; - // ### SUCCESS FLAG MEMORY LOCATIONS - uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300; - uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020; - uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340; - uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360; - uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380; - uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0; - uint256 internal constant RESULT_FLAG = 0x33c0; - // misc stuff - uint256 internal constant OMEGA_INVERSE_LOC = 0x3400; - uint256 internal constant C_ALPHA_SQR_LOC = 0x3420; - uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440; - uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460; - uint256 internal constant C_ALPHA_BASE_LOC = 0x3480; + uint256 internal constant OMEGA_INVERSE_LOC = 0x3300; + uint256 internal constant C_ALPHA_SQR_LOC = 0x3320; + uint256 internal constant C_ALPHA_CUBE_LOC = 0x3340; + uint256 internal constant C_ALPHA_QUAD_LOC = 0x3360; + uint256 internal constant C_ALPHA_BASE_LOC = 0x3380; // ### RECURSION VARIABLE MEMORY LOCATIONS - uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500; - uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520; - uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540; - uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560; - - uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580; + uint256 internal constant RECURSIVE_P1_X_LOC = 0x3400; + uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3420; + uint256 internal constant RECURSIVE_P2_X_LOC = 0x3440; + uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3460; + uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3480; // sub-identity storage - uint256 internal constant PERMUTATION_IDENTITY = 0x3600; - uint256 internal constant PLOOKUP_IDENTITY = 0x3620; - uint256 internal constant ARITHMETIC_IDENTITY = 0x3640; - uint256 internal constant SORT_IDENTITY = 0x3660; - uint256 internal constant ELLIPTIC_IDENTITY = 0x3680; - uint256 internal constant AUX_IDENTITY = 0x36a0; - uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0; - uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0; - uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700; - uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720; - uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740; - - uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760; - uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780; + uint256 internal constant PERMUTATION_IDENTITY = 0x3500; + uint256 internal constant PLOOKUP_IDENTITY = 0x3520; + uint256 internal constant ARITHMETIC_IDENTITY = 0x3540; + uint256 internal constant SORT_IDENTITY = 0x3560; + uint256 internal constant ELLIPTIC_IDENTITY = 0x3580; + uint256 internal constant AUX_IDENTITY = 0x35a0; + uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x35c0; + uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x35e0; + uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3600; + uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3620; + uint256 internal constant AUX_MEMORY_EVALUATION = 0x3640; + + uint256 internal constant QUOTIENT_EVAL_LOC = 0x3660; + uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3680; // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time - uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x36a0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x36c0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x36e0; + bytes4 internal constant INVALID_VERIFICATION_KEY_SELECTOR = 0x7e5769bf; + bytes4 internal constant POINT_NOT_ON_CURVE_SELECTOR = 0xa3dad654; bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6; bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f; bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc; - bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369; - bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec; + bytes4 internal constant PAIRING_PREAMBLE_FAILED_SELECTOR = 0x01882d81; + bytes4 internal constant OPENING_COMMITMENT_FAILED_SELECTOR = 0x4e719763; + bytes4 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd263; uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes @@ -291,17 +284,227 @@ abstract contract BaseUltraVerifier { // y^2 = x^3 + ax + b // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; + + error INVALID_VERIFICATION_KEY(); + error POINT_NOT_ON_CURVE(); error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); error PUBLIC_INPUT_GE_P(); error MOD_EXP_FAILURE(); - error EC_SCALAR_MUL_FAILURE(); - error PROOF_FAILURE(); + error PAIRING_PREAMBLE_FAILED(); + error OPENING_COMMITMENT_FAILED(); + error PAIRING_FAILED(); function getVerificationKeyHash() public pure virtual returns (bytes32); + /** + * @dev We assume that the verification key loaded by this function is constant as we only verify it on deployment + */ function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual; + constructor() { + loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC); + + // We verify that all of the EC points in the verification key lie on the bn128 curve. + assembly { + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order + + let success := 1 + + // VALIDATE Q1 + { + let x := mload(Q1_X_LOC) + let y := mload(Q1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q2 + { + let x := mload(Q2_X_LOC) + let y := mload(Q2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q3 + { + let x := mload(Q3_X_LOC) + let y := mload(Q3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q4 + { + let x := mload(Q4_X_LOC) + let y := mload(Q4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + // VALIDATE QM + { + let x := mload(QM_X_LOC) + let y := mload(QM_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QC + { + let x := mload(QC_X_LOC) + let y := mload(QC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QARITH + { + let x := mload(QARITH_X_LOC) + let y := mload(QARITH_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QSORT + { + let x := mload(QSORT_X_LOC) + let y := mload(QSORT_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QELLIPTIC + { + let x := mload(QELLIPTIC_X_LOC) + let y := mload(QELLIPTIC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QAUX + { + let x := mload(QAUX_X_LOC) + let y := mload(QAUX_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA1 + { + let x := mload(SIGMA1_X_LOC) + let y := mload(SIGMA1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA2 + { + let x := mload(SIGMA2_X_LOC) + let y := mload(SIGMA2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA3 + { + let x := mload(SIGMA3_X_LOC) + let y := mload(SIGMA3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA4 + { + let x := mload(SIGMA4_X_LOC) + let y := mload(SIGMA4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE1 + { + let x := mload(TABLE1_X_LOC) + let y := mload(TABLE1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE2 + { + let x := mload(TABLE2_X_LOC) + let y := mload(TABLE2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE3 + { + let x := mload(TABLE3_X_LOC) + let y := mload(TABLE3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE4 + { + let x := mload(TABLE4_X_LOC) + let y := mload(TABLE4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE_TYPE + { + let x := mload(TABLE_TYPE_X_LOC) + let y := mload(TABLE_TYPE_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID1 + { + let x := mload(ID1_X_LOC) + let y := mload(ID1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID2 + { + let x := mload(ID2_X_LOC) + let y := mload(ID2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID3 + { + let x := mload(ID3_X_LOC) + let y := mload(ID3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID4 + { + let x := mload(ID4_X_LOC) + let y := mload(ID4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + + if iszero(success) { + mstore(0x0, INVALID_VERIFICATION_KEY_SELECTOR) + revert(0x00, 0x04) + } + } + } + /** * @notice Verify a Ultra Plonk proof * @param _proof - The serialized proof @@ -1720,7 +1923,10 @@ abstract contract BaseUltraVerifier { let y := mload(T1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(ACCUMULATOR_X_LOC, x) mstore(add(ACCUMULATOR_X_LOC, 0x20), y) } @@ -1730,13 +1936,16 @@ abstract contract BaseUltraVerifier { let y := mload(T2_Y_LOC) // 0x1420 let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } mstore(0x40, mload(ZETA_POW_N_LOC)) // accumulator_2 = [T2].zeta^n - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40) // accumulator = [T1] + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) @@ -1746,7 +1955,10 @@ abstract contract BaseUltraVerifier { let y := mload(T3_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1762,7 +1974,10 @@ abstract contract BaseUltraVerifier { let y := mload(T4_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1778,7 +1993,10 @@ abstract contract BaseUltraVerifier { let y := mload(W1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1794,7 +2012,10 @@ abstract contract BaseUltraVerifier { let y := mload(W2_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1810,7 +2031,10 @@ abstract contract BaseUltraVerifier { let y := mload(W3_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1826,7 +2050,10 @@ abstract contract BaseUltraVerifier { let y := mload(W4_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1842,7 +2069,10 @@ abstract contract BaseUltraVerifier { let y := mload(S_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1858,7 +2088,10 @@ abstract contract BaseUltraVerifier { let y := mload(Z_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1874,7 +2107,10 @@ abstract contract BaseUltraVerifier { let y := mload(Z_LOOKUP_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1889,8 +2125,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q1_X_LOC) let y := mload(Q1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1905,8 +2140,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q2_X_LOC) let y := mload(Q2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1921,8 +2155,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q3_X_LOC) let y := mload(Q3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1937,8 +2170,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q4_X_LOC) let y := mload(Q4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1953,8 +2185,7 @@ abstract contract BaseUltraVerifier { let x := mload(QM_X_LOC) let y := mload(QM_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1969,8 +2200,7 @@ abstract contract BaseUltraVerifier { let x := mload(QC_X_LOC) let y := mload(QC_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1985,8 +2215,7 @@ abstract contract BaseUltraVerifier { let x := mload(QARITH_X_LOC) let y := mload(QARITH_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2001,8 +2230,7 @@ abstract contract BaseUltraVerifier { let x := mload(QSORT_X_LOC) let y := mload(QSORT_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2017,8 +2245,7 @@ abstract contract BaseUltraVerifier { let x := mload(QELLIPTIC_X_LOC) let y := mload(QELLIPTIC_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2033,8 +2260,7 @@ abstract contract BaseUltraVerifier { let x := mload(QAUX_X_LOC) let y := mload(QAUX_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2049,8 +2275,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA1_X_LOC) let y := mload(SIGMA1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2065,8 +2290,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA2_X_LOC) let y := mload(SIGMA2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2081,8 +2305,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA3_X_LOC) let y := mload(SIGMA3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2097,8 +2320,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA4_X_LOC) let y := mload(SIGMA4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2113,8 +2335,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE1_X_LOC) let y := mload(TABLE1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2129,8 +2350,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE2_X_LOC) let y := mload(TABLE2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2145,8 +2365,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE3_X_LOC) let y := mload(TABLE3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2161,8 +2380,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE4_X_LOC) let y := mload(TABLE4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2177,8 +2395,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE_TYPE_X_LOC) let y := mload(TABLE_TYPE_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2193,8 +2410,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID1_X_LOC) let y := mload(ID1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2209,8 +2425,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID2_X_LOC) let y := mload(ID2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2225,8 +2440,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID3_X_LOC) let y := mload(ID3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2241,8 +2455,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID4_X_LOC) let y := mload(ID4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2430,7 +2643,10 @@ abstract contract BaseUltraVerifier { // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success) + if iszero(success) { + mstore(0x0, OPENING_COMMITMENT_FAILED_SELECTOR) + revert(0x00, 0x04) + } } /** @@ -2445,13 +2661,16 @@ abstract contract BaseUltraVerifier { let y := mload(PI_Z_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } // compute zeta.[PI_Z] and add into accumulator mstore(0x40, zeta) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) @@ -2461,7 +2680,10 @@ abstract contract BaseUltraVerifier { let y := mload(PI_Z_OMEGA_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2489,7 +2711,10 @@ abstract contract BaseUltraVerifier { let y := mload(RECURSIVE_P1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2503,7 +2728,10 @@ abstract contract BaseUltraVerifier { let y := mload(RECURSIVE_P2_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2523,10 +2751,9 @@ abstract contract BaseUltraVerifier { } if iszero(success) { - mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR) + mstore(0x0, PAIRING_PREAMBLE_FAILED_SELECTOR) revert(0x00, 0x04) } - mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success) } /** @@ -2551,18 +2778,12 @@ abstract contract BaseUltraVerifier { mstore(0x160, mload(G2X_Y1_LOC)) success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20) - mstore(PAIRING_SUCCESS_FLAG, success) - mstore(RESULT_FLAG, mload(0x00)) - } - if iszero( - and( - and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)), - mload(OPENING_COMMITMENT_SUCCESS_FLAG) - ) - ) { - mstore(0x0, PROOF_FAILURE_SELECTOR) - revert(0x00, 0x04) + if iszero(and(success, mload(0x00))) { + mstore(0x0, PAIRING_FAILED_SELECTOR) + revert(0x00, 0x04) + } } + { mstore(0x00, 0x01) return(0x00, 0x20) // Proof succeeded! diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp index 3c34ad7561a..0d09d6b5752 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp @@ -1,9 +1,10 @@ #include "barretenberg/ecc/fields/field_conversion.hpp" +#include "barretenberg/plonk/proof_system/constants.hpp" namespace bb::field_conversion { -static constexpr uint64_t NUM_CONVERSION_LIMB_BITS = 68; // set to be 68 because bigfield has 68 bit limbs +static constexpr uint64_t NUM_LIMB_BITS = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION; static constexpr uint64_t TOTAL_BITS = 254; bb::fr convert_from_bn254_frs(std::span fr_vec, bb::fr* /*unused*/) @@ -34,10 +35,9 @@ bool convert_from_bn254_frs(std::span fr_vec, bool* /*unused*/) grumpkin::fr convert_from_bn254_frs(std::span fr_vec, grumpkin::fr* /*unused*/) { // Combines the two elements into one uint256_t, and then convert that to a grumpkin::fr - ASSERT(uint256_t(fr_vec[0]) < (uint256_t(1) << (NUM_CONVERSION_LIMB_BITS * 2))); // lower 136 bits - ASSERT(uint256_t(fr_vec[1]) < - (uint256_t(1) << (TOTAL_BITS - NUM_CONVERSION_LIMB_BITS * 2))); // upper 254-136=118 bits - uint256_t value = uint256_t(fr_vec[0]) + (uint256_t(fr_vec[1]) << (NUM_CONVERSION_LIMB_BITS * 2)); + ASSERT(uint256_t(fr_vec[0]) < (uint256_t(1) << (NUM_LIMB_BITS * 2))); // lower 136 bits + ASSERT(uint256_t(fr_vec[1]) < (uint256_t(1) << (TOTAL_BITS - NUM_LIMB_BITS * 2))); // upper 254-136=118 bits + uint256_t value = uint256_t(fr_vec[0]) + (uint256_t(fr_vec[1]) << (NUM_LIMB_BITS * 2)); grumpkin::fr result(value); return result; } @@ -78,7 +78,7 @@ std::vector convert_to_bn254_frs(const grumpkin::fr& val) { // Goal is to slice up the 64 bit limbs of grumpkin::fr/uint256_t to mirror the 68 bit limbs of bigfield // We accomplish this by dividing the grumpkin::fr's value into two 68*2=136 bit pieces. - constexpr uint64_t LOWER_BITS = 2 * NUM_CONVERSION_LIMB_BITS; + constexpr uint64_t LOWER_BITS = 2 * NUM_LIMB_BITS; constexpr uint256_t LOWER_MASK = (uint256_t(1) << LOWER_BITS) - 1; auto value = uint256_t(val); ASSERT(value < (uint256_t(1) << TOTAL_BITS)); @@ -113,4 +113,19 @@ std::vector convert_to_bn254_frs(const curve::Grumpkin::AffineElement& v return fr_vec; } -} // namespace bb::field_conversion \ No newline at end of file +grumpkin::fr convert_to_grumpkin_fr(const bb::fr& f) +{ + const uint64_t NUM_BITS_IN_TWO_LIMBS = 2 * NUM_LIMB_BITS; // the number of bits in 2 bigfield limbs which is 136 + + constexpr uint256_t LIMB_MASK = + (uint256_t(1) << NUM_BITS_IN_TWO_LIMBS) - 1; // split bn254_fr into two 136 bit pieces + const uint256_t value = f; + const uint256_t low = static_cast(value & LIMB_MASK); + const uint256_t hi = static_cast(value >> NUM_BITS_IN_TWO_LIMBS); + ASSERT(static_cast(low) + (static_cast(hi) << NUM_BITS_IN_TWO_LIMBS) == value); + + std::vector fr_vec{ low, hi }; + return convert_from_bn254_frs(fr_vec); +} + +} // namespace bb::field_conversion diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp index cf5b12d1def..a3abc63673d 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.hpp @@ -8,7 +8,7 @@ namespace bb::field_conversion { /** - * @brief Calculates number of bb::fr required to represent the input type + * @brief Calculates the size of a types in terms of bb::frs * @details We want to support the following types: bool, size_t, uint32_t, uint64_t, bb::fr, grumpkin::fr, * curve::BN254::AffineElement, curve::Grumpkin::AffineElement, bb::Univariate, std::array, for * FF = bb::fr/grumpkin::fr, and N is arbitrary @@ -208,4 +208,15 @@ template std::vector inline convert_to_bn254_frs(co return fr_vec; } +grumpkin::fr convert_to_grumpkin_fr(const bb::fr& f); + +template T inline convert_challenge(const bb::fr& challenge) +{ + if constexpr (std::is_same_v) { + return challenge; + } else if constexpr (std::is_same_v) { + return convert_to_grumpkin_fr(challenge); + } +} + } // namespace bb::field_conversion diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp index 0a024f82545..a2b6c3dd682 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.test.cpp @@ -131,4 +131,16 @@ TEST_F(FieldConversionTest, FieldConversionUnivariateGrumpkinFr) check_conversion(x1); } +/** + * @brief Convert challenge test for grumpkin::fr + * + */ +TEST_F(FieldConversionTest, ConvertChallengeGrumpkinFr) +{ + bb::fr chal(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits + auto result = bb::field_conversion::convert_challenge(chal); + auto expected = uint256_t(chal); + EXPECT_EQ(uint256_t(result), expected); +} + } // namespace bb::field_conversion_tests diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp index 217e2b42bd2..af92a45ae16 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_declarations.hpp @@ -214,39 +214,39 @@ template struct alignas(32) field { return result; } - BBERG_INLINE constexpr field operator*(const field& other) const noexcept; - BBERG_INLINE constexpr field operator+(const field& other) const noexcept; - BBERG_INLINE constexpr field operator-(const field& other) const noexcept; - BBERG_INLINE constexpr field operator-() const noexcept; + BB_INLINE constexpr field operator*(const field& other) const noexcept; + BB_INLINE constexpr field operator+(const field& other) const noexcept; + BB_INLINE constexpr field operator-(const field& other) const noexcept; + BB_INLINE constexpr field operator-() const noexcept; constexpr field operator/(const field& other) const noexcept; // prefix increment (++x) - BBERG_INLINE constexpr field operator++() noexcept; + BB_INLINE constexpr field operator++() noexcept; // postfix increment (x++) // NOLINTNEXTLINE - BBERG_INLINE constexpr field operator++(int) noexcept; + BB_INLINE constexpr field operator++(int) noexcept; - BBERG_INLINE constexpr field& operator*=(const field& other) noexcept; - BBERG_INLINE constexpr field& operator+=(const field& other) noexcept; - BBERG_INLINE constexpr field& operator-=(const field& other) noexcept; + BB_INLINE constexpr field& operator*=(const field& other) noexcept; + BB_INLINE constexpr field& operator+=(const field& other) noexcept; + BB_INLINE constexpr field& operator-=(const field& other) noexcept; constexpr field& operator/=(const field& other) noexcept; // NOTE: comparison operators exist so that `field` is comparible with stl methods that require them. // (e.g. std::sort) // Finite fields do not have an explicit ordering, these should *NEVER* be used in algebraic algorithms. - BBERG_INLINE constexpr bool operator>(const field& other) const noexcept; - BBERG_INLINE constexpr bool operator<(const field& other) const noexcept; - BBERG_INLINE constexpr bool operator==(const field& other) const noexcept; - BBERG_INLINE constexpr bool operator!=(const field& other) const noexcept; + BB_INLINE constexpr bool operator>(const field& other) const noexcept; + BB_INLINE constexpr bool operator<(const field& other) const noexcept; + BB_INLINE constexpr bool operator==(const field& other) const noexcept; + BB_INLINE constexpr bool operator!=(const field& other) const noexcept; - BBERG_INLINE constexpr field to_montgomery_form() const noexcept; - BBERG_INLINE constexpr field from_montgomery_form() const noexcept; + BB_INLINE constexpr field to_montgomery_form() const noexcept; + BB_INLINE constexpr field from_montgomery_form() const noexcept; - BBERG_INLINE constexpr field sqr() const noexcept; - BBERG_INLINE constexpr void self_sqr() noexcept; + BB_INLINE constexpr field sqr() const noexcept; + BB_INLINE constexpr void self_sqr() noexcept; - BBERG_INLINE constexpr field pow(const uint256_t& exponent) const noexcept; - BBERG_INLINE constexpr field pow(uint64_t exponent) const noexcept; + BB_INLINE constexpr field pow(const uint256_t& exponent) const noexcept; + BB_INLINE constexpr field pow(uint64_t exponent) const noexcept; static constexpr uint256_t modulus_minus_two = uint256_t(Params::modulus_0 - 2ULL, Params::modulus_1, Params::modulus_2, Params::modulus_3); constexpr field invert() const noexcept; @@ -259,21 +259,21 @@ template struct alignas(32) field { */ constexpr std::pair sqrt() const noexcept; - BBERG_INLINE constexpr void self_neg() noexcept; + BB_INLINE constexpr void self_neg() noexcept; - BBERG_INLINE constexpr void self_to_montgomery_form() noexcept; - BBERG_INLINE constexpr void self_from_montgomery_form() noexcept; + BB_INLINE constexpr void self_to_montgomery_form() noexcept; + BB_INLINE constexpr void self_from_montgomery_form() noexcept; - BBERG_INLINE constexpr void self_conditional_negate(uint64_t predicate) noexcept; + BB_INLINE constexpr void self_conditional_negate(uint64_t predicate) noexcept; - BBERG_INLINE constexpr field reduce_once() const noexcept; - BBERG_INLINE constexpr void self_reduce_once() noexcept; + BB_INLINE constexpr field reduce_once() const noexcept; + BB_INLINE constexpr void self_reduce_once() noexcept; - BBERG_INLINE constexpr void self_set_msb() noexcept; - [[nodiscard]] BBERG_INLINE constexpr bool is_msb_set() const noexcept; - [[nodiscard]] BBERG_INLINE constexpr uint64_t is_msb_set_word() const noexcept; + BB_INLINE constexpr void self_set_msb() noexcept; + [[nodiscard]] BB_INLINE constexpr bool is_msb_set() const noexcept; + [[nodiscard]] BB_INLINE constexpr uint64_t is_msb_set_word() const noexcept; - [[nodiscard]] BBERG_INLINE constexpr bool is_zero() const noexcept; + [[nodiscard]] BB_INLINE constexpr bool is_zero() const noexcept; static constexpr field get_root_of_unity(size_t subgroup_size) noexcept; @@ -281,15 +281,15 @@ template struct alignas(32) field { static field serialize_from_buffer(const uint8_t* buffer) { return from_buffer(buffer); } - [[nodiscard]] BBERG_INLINE std::vector to_buffer() const { return ::to_buffer(*this); } + [[nodiscard]] BB_INLINE std::vector to_buffer() const { return ::to_buffer(*this); } struct wide_array { uint64_t data[8]; // NOLINT }; - BBERG_INLINE constexpr wide_array mul_512(const field& other) const noexcept; - BBERG_INLINE constexpr wide_array sqr_512() const noexcept; + BB_INLINE constexpr wide_array mul_512(const field& other) const noexcept; + BB_INLINE constexpr wide_array sqr_512() const noexcept; - BBERG_INLINE constexpr field conditionally_subtract_from_double_modulus(const uint64_t predicate) const noexcept + BB_INLINE constexpr field conditionally_subtract_from_double_modulus(const uint64_t predicate) const noexcept { if (predicate != 0) { constexpr field p{ @@ -436,8 +436,8 @@ template struct alignas(32) field { return os; } - BBERG_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT - BBERG_INLINE static void __swap(field& src, field& dest) noexcept // NOLINT + BB_INLINE static void __copy(const field& a, field& r) noexcept { r = a; } // NOLINT + BB_INLINE static void __swap(field& src, field& dest) noexcept // NOLINT { field T = dest; dest = src; @@ -499,68 +499,62 @@ template struct alignas(32) field { {} }; - BBERG_INLINE static constexpr std::pair mul_wide(uint64_t a, uint64_t b) noexcept; + BB_INLINE static constexpr std::pair mul_wide(uint64_t a, uint64_t b) noexcept; - BBERG_INLINE static constexpr uint64_t mac( + BB_INLINE static constexpr uint64_t mac( uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& carry_out) noexcept; - BBERG_INLINE static constexpr void mac( + BB_INLINE static constexpr void mac( uint64_t a, uint64_t b, uint64_t c, uint64_t carry_in, uint64_t& out, uint64_t& carry_out) noexcept; - BBERG_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept; + BB_INLINE static constexpr uint64_t mac_mini(uint64_t a, uint64_t b, uint64_t c, uint64_t& out) noexcept; - BBERG_INLINE static constexpr void mac_mini( + BB_INLINE static constexpr void mac_mini( uint64_t a, uint64_t b, uint64_t c, uint64_t& out, uint64_t& carry_out) noexcept; - BBERG_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept; - - BBERG_INLINE static constexpr uint64_t addc(uint64_t a, - uint64_t b, - uint64_t carry_in, - uint64_t& carry_out) noexcept; - - BBERG_INLINE static constexpr uint64_t sbb(uint64_t a, - uint64_t b, - uint64_t borrow_in, - uint64_t& borrow_out) noexcept; - - BBERG_INLINE static constexpr uint64_t square_accumulate(uint64_t a, - uint64_t b, - uint64_t c, - uint64_t carry_in_lo, - uint64_t carry_in_hi, - uint64_t& carry_lo, - uint64_t& carry_hi) noexcept; - BBERG_INLINE constexpr field reduce() const noexcept; - BBERG_INLINE constexpr field add(const field& other) const noexcept; - BBERG_INLINE constexpr field subtract(const field& other) const noexcept; - BBERG_INLINE constexpr field subtract_coarse(const field& other) const noexcept; - BBERG_INLINE constexpr field montgomery_mul(const field& other) const noexcept; - BBERG_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept; - BBERG_INLINE constexpr field montgomery_square() const noexcept; + BB_INLINE static constexpr uint64_t mac_discard_lo(uint64_t a, uint64_t b, uint64_t c) noexcept; + + BB_INLINE static constexpr uint64_t addc(uint64_t a, uint64_t b, uint64_t carry_in, uint64_t& carry_out) noexcept; + + BB_INLINE static constexpr uint64_t sbb(uint64_t a, uint64_t b, uint64_t borrow_in, uint64_t& borrow_out) noexcept; + + BB_INLINE static constexpr uint64_t square_accumulate(uint64_t a, + uint64_t b, + uint64_t c, + uint64_t carry_in_lo, + uint64_t carry_in_hi, + uint64_t& carry_lo, + uint64_t& carry_hi) noexcept; + BB_INLINE constexpr field reduce() const noexcept; + BB_INLINE constexpr field add(const field& other) const noexcept; + BB_INLINE constexpr field subtract(const field& other) const noexcept; + BB_INLINE constexpr field subtract_coarse(const field& other) const noexcept; + BB_INLINE constexpr field montgomery_mul(const field& other) const noexcept; + BB_INLINE constexpr field montgomery_mul_big(const field& other) const noexcept; + BB_INLINE constexpr field montgomery_square() const noexcept; #if (BBERG_NO_ASM == 0) - BBERG_INLINE static field asm_mul(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_sqr(const field& a) noexcept; - BBERG_INLINE static field asm_add(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_sub(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept; - BBERG_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static field asm_add_without_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_sqr(const field& a) noexcept; - BBERG_INLINE static void asm_self_add(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_sub(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_sqr_with_coarse_reduction(const field& a) noexcept; - BBERG_INLINE static void asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept; - BBERG_INLINE static void asm_self_add_without_reduction(const field& a, const field& b) noexcept; - - BBERG_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept; - BBERG_INLINE static field asm_reduce_once(const field& a) noexcept; - BBERG_INLINE static void asm_self_reduce_once(const field& a) noexcept; + BB_INLINE static field asm_mul(const field& a, const field& b) noexcept; + BB_INLINE static field asm_sqr(const field& a) noexcept; + BB_INLINE static field asm_add(const field& a, const field& b) noexcept; + BB_INLINE static field asm_sub(const field& a, const field& b) noexcept; + BB_INLINE static field asm_mul_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static field asm_sqr_with_coarse_reduction(const field& a) noexcept; + BB_INLINE static field asm_add_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static field asm_sub_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static field asm_add_without_reduction(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sqr(const field& a) noexcept; + BB_INLINE static void asm_self_add(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sub(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_mul_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sqr_with_coarse_reduction(const field& a) noexcept; + BB_INLINE static void asm_self_add_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_sub_with_coarse_reduction(const field& a, const field& b) noexcept; + BB_INLINE static void asm_self_add_without_reduction(const field& a, const field& b) noexcept; + + BB_INLINE static void asm_conditional_negate(field& r, uint64_t predicate) noexcept; + BB_INLINE static field asm_reduce_once(const field& a) noexcept; + BB_INLINE static void asm_self_reduce_once(const field& a) noexcept; static constexpr uint64_t zero_reference = 0x00ULL; #endif static constexpr size_t COSET_GENERATOR_SIZE = 15; diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp index 2149e131241..f7e8b08a718 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/common/op_count.hpp" #include "barretenberg/common/slab_allocator.hpp" #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" @@ -25,6 +26,7 @@ namespace bb { **/ template constexpr field field::operator*(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f*"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { // >= 255-bits or <= 64-bits. @@ -39,6 +41,7 @@ template constexpr field field::operator*(const field& other) co template constexpr field& field::operator*=(const field& other) noexcept { + BB_OP_COUNT_TRACK_NAME("f*="); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { // >= 255-bits or <= 64-bits. @@ -60,6 +63,7 @@ template constexpr field& field::operator*=(const field& other) **/ template constexpr field field::sqr() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::sqr"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { return montgomery_square(); @@ -73,6 +77,7 @@ template constexpr field field::sqr() const noexcept template constexpr void field::self_sqr() noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_sqr"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { *this = montgomery_square(); @@ -92,6 +97,7 @@ template constexpr void field::self_sqr() noexcept **/ template constexpr field field::operator+(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f+"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { return add(other); @@ -105,6 +111,7 @@ template constexpr field field::operator+(const field& other) co template constexpr field& field::operator+=(const field& other) noexcept { + BB_OP_COUNT_TRACK_NAME("f+="); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { (*this) = operator+(other); @@ -120,12 +127,14 @@ template constexpr field& field::operator+=(const field& other) template constexpr field field::operator++() noexcept { + BB_OP_COUNT_TRACK_NAME("++f"); return *this += 1; } // NOLINTNEXTLINE(cert-dcl21-cpp) circular linting errors. If const is added, linter suggests removing template constexpr field field::operator++(int) noexcept { + BB_OP_COUNT_TRACK_NAME("f++"); field value_before_incrementing = *this; *this += 1; return value_before_incrementing; @@ -138,6 +147,7 @@ template constexpr field field::operator++(int) noexcept **/ template constexpr field field::operator-(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f-"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { return subtract_coarse(other); // modulus - *this; @@ -151,6 +161,7 @@ template constexpr field field::operator-(const field& other) co template constexpr field field::operator-() const noexcept { + BB_OP_COUNT_TRACK_NAME("-f"); if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { constexpr field p{ modulus.data[0], modulus.data[1], modulus.data[2], modulus.data[3] }; @@ -179,6 +190,7 @@ template constexpr field field::operator-() const noexcept template constexpr field& field::operator-=(const field& other) noexcept { + BB_OP_COUNT_TRACK_NAME("f-="); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { *this = subtract_coarse(other); // subtract(other); @@ -194,6 +206,7 @@ template constexpr field& field::operator-=(const field& other) template constexpr void field::self_neg() noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_neg"); if constexpr ((T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { constexpr field p{ modulus.data[0], modulus.data[1], modulus.data[2], modulus.data[3] }; @@ -206,6 +219,7 @@ template constexpr void field::self_neg() noexcept template constexpr void field::self_conditional_negate(const uint64_t predicate) noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_conditional_negate"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { *this = predicate ? -(*this) : *this; // NOLINT @@ -231,6 +245,7 @@ template constexpr void field::self_conditional_negate(const uint64 */ template constexpr bool field::operator>(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f>"); const field left = reduce_once(); const field right = other.reduce_once(); const bool t0 = left.data[3] > right.data[3]; @@ -260,6 +275,7 @@ template constexpr bool field::operator<(const field& other) const template constexpr bool field::operator==(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f=="); const field left = reduce_once(); const field right = other.reduce_once(); return (left.data[0] == right.data[0]) && (left.data[1] == right.data[1]) && (left.data[2] == right.data[2]) && @@ -273,6 +289,7 @@ template constexpr bool field::operator!=(const field& other) const template constexpr field field::to_montgomery_form() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::to_montgomery_form"); constexpr field r_squared{ T::r_squared_0, T::r_squared_1, T::r_squared_2, T::r_squared_3 }; field result = *this; @@ -290,12 +307,14 @@ template constexpr field field::to_montgomery_form() const noexc template constexpr field field::from_montgomery_form() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::from_montgomery_form"); constexpr field one_raw{ 1, 0, 0, 0 }; return operator*(one_raw).reduce_once(); } template constexpr void field::self_to_montgomery_form() noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_to_montgomery_form"); constexpr field r_squared{ T::r_squared_0, T::r_squared_1, T::r_squared_2, T::r_squared_3 }; self_reduce_once(); self_reduce_once(); @@ -306,6 +325,7 @@ template constexpr void field::self_to_montgomery_form() noexcept template constexpr void field::self_from_montgomery_form() noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_from_montgomery_form"); constexpr field one_raw{ 1, 0, 0, 0 }; *this *= one_raw; self_reduce_once(); @@ -313,6 +333,7 @@ template constexpr void field::self_from_montgomery_form() noexcept template constexpr field field::reduce_once() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::reduce_once"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { return reduce(); @@ -326,6 +347,7 @@ template constexpr field field::reduce_once() const noexcept template constexpr void field::self_reduce_once() noexcept { + BB_OP_COUNT_TRACK_NAME("f::self_reduce_once"); if constexpr (BBERG_NO_ASM || (T::modulus_3 >= 0x4000000000000000ULL) || (T::modulus_1 == 0 && T::modulus_2 == 0 && T::modulus_3 == 0)) { *this = reduce(); @@ -340,7 +362,7 @@ template constexpr void field::self_reduce_once() noexcept template constexpr field field::pow(const uint256_t& exponent) const noexcept { - + BB_OP_COUNT_TRACK_NAME("f::pow"); field accumulator{ data[0], data[1], data[2], data[3] }; field to_mul{ data[0], data[1], data[2], data[3] }; const uint64_t maximum_set_bit = exponent.get_msb(); @@ -366,6 +388,7 @@ template constexpr field field::pow(const uint64_t exponent) con template constexpr field field::invert() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::invert"); if (*this == zero()) { throw_or_abort("Trying to invert zero in the field"); } @@ -379,6 +402,7 @@ template void field::batch_invert(field* coeffs, const size_t n) no template void field::batch_invert(std::span coeffs) noexcept { + BB_OP_COUNT_TRACK_NAME("f::batch_invert"); const size_t n = coeffs.size(); auto temporaries_ptr = std::static_pointer_cast(get_mem_slab(n * sizeof(field))); @@ -427,6 +451,7 @@ template void field::batch_invert(std::span coeffs) noexcept template constexpr field field::tonelli_shanks_sqrt() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::tonelli_shanks_sqrt"); // Tonelli-shanks algorithm begins by finding a field element Q and integer S, // such that (p - 1) = Q.2^{s} @@ -506,6 +531,7 @@ template constexpr field field::tonelli_shanks_sqrt() const noex template constexpr std::pair> field::sqrt() const noexcept { + BB_OP_COUNT_TRACK_NAME("f::sqrt"); field root; if constexpr ((T::modulus_0 & 0x3UL) == 0x3UL) { constexpr uint256_t sqrt_exponent = (modulus + uint256_t(1)) >> 2; @@ -522,11 +548,13 @@ template constexpr std::pair> field::sqrt() const no template constexpr field field::operator/(const field& other) const noexcept { + BB_OP_COUNT_TRACK_NAME("f/"); return operator*(other.invert()); } template constexpr field& field::operator/=(const field& other) noexcept { + BB_OP_COUNT_TRACK_NAME("f/="); *this = operator/(other); return *this; } @@ -563,6 +591,7 @@ template constexpr field field::get_root_of_unity(size_t subgrou template field field::random_element(numeric::RNG* engine) noexcept { + BB_OP_COUNT_TRACK_NAME("f::random_element"); if (engine == nullptr) { engine = &numeric::get_randomness(); } @@ -575,6 +604,7 @@ template field field::random_element(numeric::RNG* engine) noexc template constexpr size_t field::primitive_root_log_size() noexcept { + BB_OP_COUNT_TRACK_NAME("f::primitive_root_log_size"); uint256_t target = modulus - 1; size_t result = 0; while (!target.get_bit(result)) { diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp index 8eab68d1b24..f1bed6aa602 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_impl_generic.hpp @@ -4,6 +4,8 @@ #include #include "./field_impl.hpp" +#include "barretenberg/common/op_count.hpp" + namespace bb { // NOLINTBEGIN(readability-implicit-bool-conversion) @@ -103,6 +105,7 @@ constexpr uint64_t field::addc(const uint64_t a, const uint64_t carry_in, uint64_t& carry_out) noexcept { + BB_OP_COUNT_TRACK(); #if defined(__SIZEOF_INT128__) && !defined(__wasm__) uint128_t res = static_cast(a) + static_cast(b) + static_cast(carry_in); carry_out = static_cast(res >> 64); diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp index 637d3dda0a4..0c34effbfaa 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp @@ -84,11 +84,11 @@ template class alignas(32) element { constexpr element normalize() const noexcept; static element infinity(); - BBERG_INLINE constexpr element set_infinity() const noexcept; - BBERG_INLINE constexpr void self_set_infinity() noexcept; - [[nodiscard]] BBERG_INLINE constexpr bool is_point_at_infinity() const noexcept; - [[nodiscard]] BBERG_INLINE constexpr bool on_curve() const noexcept; - BBERG_INLINE constexpr bool operator==(const element& other) const noexcept; + BB_INLINE constexpr element set_infinity() const noexcept; + BB_INLINE constexpr void self_set_infinity() noexcept; + [[nodiscard]] BB_INLINE constexpr bool is_point_at_infinity() const noexcept; + [[nodiscard]] BB_INLINE constexpr bool on_curve() const noexcept; + BB_INLINE constexpr bool operator==(const element& other) const noexcept; static void batch_normalize(element* elements, size_t num_elements) noexcept; static void batch_affine_add(const std::span>& first_group, diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp index 422065e4273..ec9eba4ffac 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/common/op_count.hpp" #include "barretenberg/common/thread.hpp" #include "barretenberg/ecc/groups/element.hpp" #include "element.hpp" @@ -444,6 +445,7 @@ constexpr element element::operator+=(const element& other template constexpr element element::operator+(const element& other) const noexcept { + BB_OP_COUNT_TRACK(); element result(*this); return (result += other); } @@ -458,6 +460,7 @@ constexpr element element::operator-=(const element& other template constexpr element element::operator-(const element& other) const noexcept { + BB_OP_COUNT_TRACK(); element result(*this); return (result -= other); } diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/group.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/group.hpp index ce13dfec331..27cd56f8ca8 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/group.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/group.hpp @@ -115,9 +115,9 @@ template & state, bool handle_edge_cases) { + BB_OP_COUNT_TRACK(); using Group = typename Curve::Group; using Element = typename Curve::Element; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp index ec5cba49084..58e525278e9 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.cpp @@ -71,7 +71,7 @@ template void ECCVMProver_::execute_wire_commitme template void ECCVMProver_::execute_log_derivative_commitments_round() { // Compute and add beta to relation parameters - auto [beta, gamma] = challenges_to_field_elements(transcript->get_challenges("beta", "gamma")); + auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); // TODO(#583)(@zac-williamson): fix Transcript to be able to generate more than 2 challenges per round! oof. auto beta_sqr = beta * beta; @@ -110,10 +110,10 @@ template void ECCVMProver_::execute_relation_chec using Sumcheck = SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } @@ -128,7 +128,7 @@ template void ECCVMProver_::execute_univariatizat const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; // Generate batching challenge ρ and powers 1,ρ,…,ρᵐ⁻¹ - FF rho = transcript->get_challenge("rho"); + FF rho = transcript->template get_challenge("rho"); std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); // Batch the unshifted polynomials and the to-be-shifted polynomials using ρ @@ -168,7 +168,7 @@ template void ECCVMProver_::execute_univariatizat * */ template void ECCVMProver_::execute_pcs_evaluation_round() { - const FF r_challenge = transcript->get_challenge("Gemini:r"); + const FF r_challenge = transcript->template get_challenge("Gemini:r"); gemini_output = Gemini::compute_fold_polynomial_evaluations( sumcheck_output.challenge, std::move(gemini_polynomials), r_challenge); @@ -185,7 +185,7 @@ template void ECCVMProver_::execute_pcs_evaluatio * */ template void ECCVMProver_::execute_shplonk_batched_quotient_round() { - nu_challenge = transcript->get_challenge("Shplonk:nu"); + nu_challenge = transcript->template get_challenge("Shplonk:nu"); batched_quotient_Q = Shplonk::compute_batched_quotient(gemini_output.opening_pairs, gemini_output.witnesses, nu_challenge); @@ -200,7 +200,7 @@ template void ECCVMProver_::execute_shplonk_batch * */ template void ECCVMProver_::execute_shplonk_partial_evaluation_round() { - const FF z_challenge = transcript->get_challenge("Shplonk:z"); + const FF z_challenge = transcript->template get_challenge("Shplonk:z"); shplonk_output = Shplonk::compute_partially_evaluated_batched_quotient( gemini_output.opening_pairs, gemini_output.witnesses, std::move(batched_quotient_Q), nu_challenge, z_challenge); @@ -232,7 +232,7 @@ template void ECCVMProver_::execute_transcript_co transcript->send_to_verifier("Translation:hack_commitment", commitment_key->commit(hack)); // Get the challenge at which we evaluate the polynomials as univariates - evaluation_challenge_x = transcript->get_challenge("Translation:evaluation_challenge_x"); + evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); translation_evaluations.op = key->transcript_op.evaluate(evaluation_challenge_x); translation_evaluations.Px = key->transcript_Px.evaluate(evaluation_challenge_x); @@ -249,7 +249,7 @@ template void ECCVMProver_::execute_transcript_co transcript->send_to_verifier("Translation:hack_evaluation", hack.evaluate(evaluation_challenge_x)); // Get another challenge for batching the univariate claims - FF ipa_batching_challenge = transcript->get_challenge("Translation:ipa_batching_challenge"); + FF ipa_batching_challenge = transcript->template get_challenge("Translation:ipa_batching_challenge"); // Collect the polynomials and evaluations to be batched RefArray univariate_polynomials{ key->transcript_op, key->transcript_Px, key->transcript_Py, @@ -271,7 +271,7 @@ template void ECCVMProver_::execute_transcript_co commitment_key, { evaluation_challenge_x, batched_evaluation }, batched_univariate, transcript); // Get another challenge for batching the univariate claims - translation_batching_challenge_v = transcript->get_challenge("Translation:batching_challenge"); + translation_batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); } template HonkProof& ECCVMProver_::export_proof() diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp index a5051d6d4f9..3d8aeead828 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_prover.hpp @@ -30,17 +30,17 @@ template class ECCVMProver_ { const std::shared_ptr& commitment_key, const std::shared_ptr& transcript = std::make_shared()); - BBERG_PROFILE void execute_preamble_round(); - BBERG_PROFILE void execute_wire_commitments_round(); - BBERG_PROFILE void execute_log_derivative_commitments_round(); - BBERG_PROFILE void execute_grand_product_computation_round(); - BBERG_PROFILE void execute_relation_check_rounds(); - BBERG_PROFILE void execute_univariatization_round(); - BBERG_PROFILE void execute_pcs_evaluation_round(); - BBERG_PROFILE void execute_shplonk_batched_quotient_round(); - BBERG_PROFILE void execute_shplonk_partial_evaluation_round(); - BBERG_PROFILE void execute_final_pcs_round(); - BBERG_PROFILE void execute_transcript_consistency_univariate_opening_round(); + BB_PROFILE void execute_preamble_round(); + BB_PROFILE void execute_wire_commitments_round(); + BB_PROFILE void execute_log_derivative_commitments_round(); + BB_PROFILE void execute_grand_product_computation_round(); + BB_PROFILE void execute_relation_check_rounds(); + BB_PROFILE void execute_univariatization_round(); + BB_PROFILE void execute_pcs_evaluation_round(); + BB_PROFILE void execute_shplonk_batched_quotient_round(); + BB_PROFILE void execute_shplonk_partial_evaluation_round(); + BB_PROFILE void execute_final_pcs_round(); + BB_PROFILE void execute_transcript_consistency_univariate_opening_round(); HonkProof& export_proof(); HonkProof& construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp index 73dafdf3c68..f1ab178db34 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_transcript.test.cpp @@ -299,7 +299,7 @@ TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) // initialized with random value sent to verifier auto transcript = Flavor::Transcript::prover_init_empty(); // test a bunch of challenges - auto challenges = transcript->get_challenges("a", "b", "c", "d", "e", "f"); + auto challenges = transcript->template get_challenges("a", "b", "c", "d", "e", "f"); // check they are not 0 for (size_t i = 0; i < challenges.size(); ++i) { ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; @@ -307,7 +307,7 @@ TYPED_TEST(ECCVMTranscriptTests, ChallengeGenerationTest) constexpr uint32_t random_val{ 17 }; // arbitrary transcript->send_to_verifier("random val", random_val); // test more challenges - auto [a, b, c] = challenges_to_field_elements(transcript->get_challenges("a", "b", "c")); + auto [a, b, c] = transcript->template get_challenges("a", "b", "c"); ASSERT_NE(a, 0) << "Challenge a is 0"; ASSERT_NE(b, 0) << "Challenge b is 0"; diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp index 58cf1e656c3..71ce6e2ae6a 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_verifier.cpp @@ -137,7 +137,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP commitments.lookup_read_counts_1 = receive_commitment(commitment_labels.lookup_read_counts_1); // Get challenge for sorted list batching and wire four memory records - auto [beta, gamma] = challenges_to_field_elements(transcript->get_challenges("beta", "gamma")); + auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); relation_parameters.gamma = gamma; auto beta_sqr = beta * beta; @@ -155,10 +155,10 @@ template bool ECCVMVerifier_::verify_proof(const HonkP // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, purported_evaluations, sumcheck_verified] = @@ -178,7 +178,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP auto batched_commitment_to_be_shifted = GroupElement::zero(); const size_t NUM_POLYNOMIALS = Flavor::NUM_ALL_ENTITIES; // Compute powers of batching challenge rho - FF rho = transcript->get_challenge("rho"); + FF rho = transcript->template get_challenge("rho"); std::vector rhos = gemini::powers_of_rho(rho, NUM_POLYNOMIALS); // Compute batched multivariate evaluation @@ -238,7 +238,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP { auto hack_commitment = receive_commitment("Translation:hack_commitment"); - FF evaluation_challenge_x = transcript->get_challenge("Translation:evaluation_challenge_x"); + FF evaluation_challenge_x = transcript->template get_challenge("Translation:evaluation_challenge_x"); // Construct arrays of commitments and evaluations to be batched const size_t NUM_UNIVARIATES = 6; @@ -256,7 +256,7 @@ template bool ECCVMVerifier_::verify_proof(const HonkP }; // Get another challenge for batching the univariate claims - FF ipa_batching_challenge = transcript->get_challenge("Translation:ipa_batching_challenge"); + FF ipa_batching_challenge = transcript->template get_challenge("Translation:ipa_batching_challenge"); // Construct batched commitment and batched evaluation auto batched_commitment = transcript_commitments[0]; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp index ba3c2df1abf..ad1feee32f3 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp @@ -520,7 +520,7 @@ template class ECCVMBa * @brief Derived class that defines proof structure for ECCVM proofs, as well as supporting functions. * */ - class Transcript : public BaseTranscript { + class Transcript : public NativeTranscript { public: uint32_t circuit_size; Commitment transcript_add_comm; @@ -606,7 +606,7 @@ template class ECCVMBa Commitment shplonk_q_comm; Commitment kzg_w_comm; // the rest are only for Grumpkin - uint64_t ipa_poly_degree; + uint32_t ipa_poly_degree; std::vector ipa_l_comms; std::vector ipa_r_comms; FF ipa_a_0_eval; @@ -614,200 +614,200 @@ template class ECCVMBa Transcript() = default; Transcript(const HonkProof& proof) - : BaseTranscript(proof) + : NativeTranscript(proof) {} void deserialize_full_transcript() { // take current proof and put them into the struct size_t num_frs_read = 0; - circuit_size = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); + circuit_size = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); size_t log_n = numeric::get_msb(circuit_size); - transcript_add_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_mul_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_eq_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_collision_check_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_msm_transition_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_pc_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_msm_count_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_Px_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_Py_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_z1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_z2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_z1zero_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_z2zero_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_op_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_accumulator_x_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_accumulator_y_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_msm_x_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_msm_y_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_pc_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_point_transition_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_round_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_scalar_sum_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s1hi_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s1lo_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s2hi_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s2lo_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s3hi_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s3lo_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s4hi_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_s4lo_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_skew_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_dx_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_dy_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_tx_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_ty_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_transition_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_add_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_double_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_skew_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_accumulator_x_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_accumulator_y_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_pc_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_size_of_msm_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_count_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_round_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_add1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_add2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_add3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_add4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_x1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_y1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_x2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_y2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_x3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_y3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_x4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_y4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_collision_x1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_collision_x2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_collision_x3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_collision_x4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_lambda1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_lambda2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_lambda3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_lambda4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_slice1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_slice2_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_slice3_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - msm_slice4_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_accumulator_empty_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - transcript_reset_accumulator_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - precompute_select_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - lookup_read_counts_0_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - lookup_read_counts_1_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - lookup_inverses_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); - z_perm_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); + transcript_add_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_mul_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_eq_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_collision_check_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_msm_transition_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_pc_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_msm_count_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_Px_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_Py_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_z1_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_z2_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_z1zero_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_z2zero_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_op_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_accumulator_x_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_accumulator_y_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_msm_x_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_msm_y_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_pc_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_point_transition_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_round_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_scalar_sum_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s1hi_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s1lo_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s2hi_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s2lo_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s3hi_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s3lo_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s4hi_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_s4lo_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_skew_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_dx_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_dy_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_tx_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_ty_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_transition_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_add_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_double_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_skew_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_accumulator_x_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_accumulator_y_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_pc_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_size_of_msm_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_count_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_round_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_add1_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_add2_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_add3_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_add4_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_x1_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_y1_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_x2_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_y2_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_x3_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_y3_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_x4_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_y4_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); + msm_collision_x1_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_collision_x2_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_collision_x3_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_collision_x4_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_lambda1_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_lambda2_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_lambda3_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_lambda4_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_slice1_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_slice2_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_slice3_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + msm_slice4_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_accumulator_empty_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + transcript_reset_accumulator_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + precompute_select_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + lookup_read_counts_0_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + lookup_read_counts_1_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + lookup_inverses_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); + z_perm_comm = NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, + num_frs_read); for (size_t i = 0; i < log_n; ++i) { - sumcheck_univariates.emplace_back( - BaseTranscript::template deserialize_from_buffer< - bb::Univariate>(BaseTranscript::proof_data, num_frs_read)); + sumcheck_univariates.emplace_back(NativeTranscript::template deserialize_from_buffer< + bb::Univariate>( + NativeTranscript::proof_data, num_frs_read)); } - sumcheck_evaluations = BaseTranscript::template deserialize_from_buffer>( - BaseTranscript::proof_data, num_frs_read); + sumcheck_evaluations = NativeTranscript::template deserialize_from_buffer>( + NativeTranscript::proof_data, num_frs_read); for (size_t i = 0; i < log_n - 1; ++i) { - gemini_univariate_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( - BaseTranscript::proof_data, num_frs_read)); + gemini_univariate_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } for (size_t i = 0; i < log_n; ++i) { gemini_a_evals.emplace_back( - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read)); + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read)); } - shplonk_q_comm = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); + shplonk_q_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); if (std::is_same>::value) { - kzg_w_comm = BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, - num_frs_read); + kzg_w_comm = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); } else if (std::is_same>::value) { - ipa_poly_degree = BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, - num_frs_read); + ipa_poly_degree = NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read); auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); for (size_t i = 0; i < log_poly_degree; ++i) { - ipa_l_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( - BaseTranscript::proof_data, num_frs_read)); - ipa_r_comms.emplace_back(BaseTranscript::template deserialize_from_buffer( - BaseTranscript::proof_data, num_frs_read)); + ipa_l_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); + ipa_r_comms.emplace_back(NativeTranscript::template deserialize_from_buffer( + NativeTranscript::proof_data, num_frs_read)); } ipa_a_0_eval = - BaseTranscript::template deserialize_from_buffer(BaseTranscript::proof_data, num_frs_read); + NativeTranscript::template deserialize_from_buffer(NativeTranscript::proof_data, num_frs_read); } else { throw_or_abort("Unsupported PCS"); } @@ -815,111 +815,117 @@ template class ECCVMBa void serialize_full_transcript() { - size_t old_proof_length = BaseTranscript::proof_data.size(); - BaseTranscript::proof_data.clear(); + size_t old_proof_length = NativeTranscript::proof_data.size(); + NativeTranscript::proof_data.clear(); size_t log_n = numeric::get_msb(circuit_size); - BaseTranscript::template serialize_to_buffer(circuit_size, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_add_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_mul_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_eq_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_collision_check_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_msm_transition_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_pc_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_msm_count_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_Px_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_Py_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_z1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_z2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_z1zero_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_z2zero_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_op_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_accumulator_x_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_accumulator_y_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_msm_x_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_msm_y_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_pc_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_point_transition_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_round_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_scalar_sum_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s1hi_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s1lo_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s2hi_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s2lo_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s3hi_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s3lo_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s4hi_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_s4lo_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_skew_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_dx_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_dy_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_tx_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_ty_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_transition_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_add_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_double_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_skew_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_accumulator_x_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_accumulator_y_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_pc_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_size_of_msm_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_count_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_round_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_add1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_add2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_add3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_add4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_x1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_y1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_x2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_y2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_x3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_y3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_x4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_y4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_collision_x1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_collision_x2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_collision_x3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_collision_x4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_lambda1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_lambda2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_lambda3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_lambda4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_slice1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_slice2_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_slice3_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(msm_slice4_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_accumulator_empty_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(transcript_reset_accumulator_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(precompute_select_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(lookup_read_counts_0_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(lookup_read_counts_1_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(lookup_inverses_comm, BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(z_perm_comm, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(circuit_size, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_add_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_mul_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_eq_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_collision_check_comm, + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_msm_transition_comm, + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_pc_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_msm_count_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_Px_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_Py_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_z1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_z2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_z1zero_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_z2zero_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_op_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_accumulator_x_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_accumulator_y_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_msm_x_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_msm_y_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_pc_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_point_transition_comm, + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_round_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_scalar_sum_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s1hi_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s1lo_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s2hi_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s2lo_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s3hi_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s3lo_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s4hi_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_s4lo_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_skew_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_dx_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_dy_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_tx_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_ty_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_transition_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_add_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_double_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_skew_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_accumulator_x_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_accumulator_y_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_pc_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_size_of_msm_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_count_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_round_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_add1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_add2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_add3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_add4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_x1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_y1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_x2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_y2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_x3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_y3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_x4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_y4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_collision_x1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_collision_x2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_collision_x3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_collision_x4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_lambda1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_lambda2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_lambda3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_lambda4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_slice1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_slice2_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_slice3_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(msm_slice4_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_accumulator_empty_comm, + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(transcript_reset_accumulator_comm, + NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(precompute_select_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(lookup_read_counts_0_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(lookup_read_counts_1_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(lookup_inverses_comm, NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(z_perm_comm, NativeTranscript::proof_data); for (size_t i = 0; i < log_n; ++i) { - BaseTranscript::template serialize_to_buffer(sumcheck_univariates[i], BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(sumcheck_univariates[i], NativeTranscript::proof_data); } - BaseTranscript::template serialize_to_buffer(sumcheck_evaluations, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(sumcheck_evaluations, NativeTranscript::proof_data); for (size_t i = 0; i < log_n - 1; ++i) { - BaseTranscript::template serialize_to_buffer(gemini_univariate_comms[i], BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(gemini_univariate_comms[i], + NativeTranscript::proof_data); } for (size_t i = 0; i < log_n; ++i) { - BaseTranscript::template serialize_to_buffer(gemini_a_evals[i], BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(gemini_a_evals[i], NativeTranscript::proof_data); } - BaseTranscript::template serialize_to_buffer(shplonk_q_comm, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(shplonk_q_comm, NativeTranscript::proof_data); if (std::is_same>::value) { - BaseTranscript::template serialize_to_buffer(kzg_w_comm, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(kzg_w_comm, NativeTranscript::proof_data); } else if (std::is_same>::value) { - BaseTranscript::template serialize_to_buffer(ipa_poly_degree, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_poly_degree, NativeTranscript::proof_data); auto log_poly_degree = static_cast(numeric::get_msb(ipa_poly_degree)); for (size_t i = 0; i < log_poly_degree; ++i) { - BaseTranscript::template serialize_to_buffer(ipa_l_comms[i], BaseTranscript::proof_data); - BaseTranscript::template serialize_to_buffer(ipa_r_comms[i], BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_l_comms[i], NativeTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_r_comms[i], NativeTranscript::proof_data); } - BaseTranscript::template serialize_to_buffer(ipa_a_0_eval, BaseTranscript::proof_data); + NativeTranscript::template serialize_to_buffer(ipa_a_0_eval, NativeTranscript::proof_data); } - ASSERT(BaseTranscript::proof_data.size() == old_proof_length); + ASSERT(NativeTranscript::proof_data.size() == old_proof_length); } }; }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp index a249820db28..1ee03bc93b8 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/AvmMini_flavor.hpp @@ -643,7 +643,7 @@ class AvmMiniFlavor { } }; - class Transcript : public BaseTranscript { + class Transcript : public NativeTranscript { public: uint32_t circuit_size; @@ -721,7 +721,7 @@ class AvmMiniFlavor { Transcript() = default; Transcript(const std::vector& proof) - : BaseTranscript(proof) + : NativeTranscript(proof) {} void deserialize_full_transcript() diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp index 83f540cfd8b..1d88605d122 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/Toy_flavor.hpp @@ -256,7 +256,7 @@ class ToyFlavor { } }; - class Transcript : public BaseTranscript { + class Transcript : public NativeTranscript { public: uint32_t circuit_size; @@ -286,7 +286,7 @@ class ToyFlavor { Transcript() = default; Transcript(const std::vector& proof) - : BaseTranscript(proof) + : NativeTranscript(proof) {} void deserialize_full_transcript() diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp index 8f0fe89209d..8ea63c7c8b1 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp @@ -1136,6 +1136,6 @@ class GoblinTranslatorFlavor { } }; - using Transcript = BaseTranscript; + using Transcript = NativeTranscript; }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 5ff14f552aa..ed28295cd6b 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -478,7 +478,7 @@ class GoblinUltraFlavor { * @brief Derived class that defines proof structure for GoblinUltra proofs, as well as supporting functions. * Note: Made generic for use in GoblinUltraRecursive. */ - template class Transcript_ : public BaseTranscript { + template class Transcript_ : public NativeTranscript { public: uint32_t circuit_size; uint32_t public_input_size; @@ -507,7 +507,7 @@ class GoblinUltraFlavor { Transcript_() = default; Transcript_(const HonkProof& proof) - : BaseTranscript(proof) + : NativeTranscript(proof) {} void deserialize_full_transcript() diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 16cfefff849..bf47f5da3c9 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -167,7 +167,7 @@ template class GoblinUltraRecursiveFlavor_ { // Reuse the VerifierCommitments from GoblinUltra using VerifierCommitments = GoblinUltraFlavor::VerifierCommitments_; // Reuse the transcript from GoblinUltra - using Transcript = bb::stdlib::recursion::honk::Transcript; + using Transcript = bb::BaseTranscript>; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index ae2232f8685..d078ff3c5cd 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -458,7 +458,7 @@ class UltraFlavor { * @brief Derived class that defines proof structure for Ultra proofs, as well as supporting functions. * */ - class Transcript : public BaseTranscript { + class Transcript : public NativeTranscript { public: // Transcript objects defined as public member variables for easy access and modification uint32_t circuit_size; @@ -482,7 +482,7 @@ class UltraFlavor { // Used by verifier to initialize the transcript Transcript(const std::vector& proof) - : BaseTranscript(proof) + : NativeTranscript(proof) {} static std::shared_ptr prover_init_empty() @@ -496,7 +496,7 @@ class UltraFlavor { static std::shared_ptr verifier_init_empty(const std::shared_ptr& transcript) { auto verifier_transcript = std::make_shared(transcript->proof_data); - [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover("Init"); + [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover("Init"); return verifier_transcript; }; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index 0c8aede2d37..e1ec3530e51 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -17,8 +17,6 @@ #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/srs/factories/crs_factory.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" -#include "barretenberg/transcript/transcript.hpp" #include #include @@ -29,6 +27,7 @@ #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" namespace bb { @@ -419,7 +418,7 @@ template class UltraRecursiveFlavor_ { } }; - using Transcript = bb::stdlib::recursion::honk::Transcript; + using Transcript = bb::BaseTranscript>; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp deleted file mode 100644 index dcc1323d781..00000000000 --- a/barretenberg/cpp/src/barretenberg/goblin/full_goblin_recursion.test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "barretenberg/eccvm/eccvm_composer.hpp" -#include "barretenberg/goblin/goblin.hpp" -#include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/goblin/translation_evaluations.hpp" -#include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" -#include "barretenberg/translator_vm/goblin_translator_composer.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" - -#include - -using namespace bb; - -class GoblinRecursionTests : public ::testing::Test { - protected: - static void SetUpTestSuite() - { - srs::init_crs_factory("../srs_db/ignition"); - srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); - } - - using Curve = curve::BN254; - using FF = Curve::ScalarField; - using GoblinUltraBuilder = GoblinUltraCircuitBuilder; - using KernelInput = Goblin::AccumulationOutput; -}; - -/** * @brief A full Goblin test that mimicks the basic aztec client architecture - * - */ -TEST_F(GoblinRecursionTests, Pseudo) -{ - Goblin goblin; - - // Construct an initial circuit; its proof will be recursively verified by the first kernel - GoblinUltraBuilder initial_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_simple_initial_circuit(initial_circuit); - KernelInput kernel_input = goblin.accumulate(initial_circuit); - - // Construct a series of simple Goblin circuits; generate and verify their proofs - size_t NUM_CIRCUITS = 2; - for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { - // Construct a circuit with logic resembling that of the "kernel circuit" - GoblinUltraBuilder circuit_builder{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(circuit_builder, kernel_input, kernel_input); - - // Construct proof of the current kernel circuit to be recursively verified by the next one - kernel_input = goblin.accumulate(circuit_builder); - } - - Goblin::Proof proof = goblin.prove(); - // Verify the final ultra proof - GoblinUltraVerifier ultra_verifier{ kernel_input.verification_key }; - bool ultra_verified = ultra_verifier.verify_proof(kernel_input.proof); - // Verify the goblin proof (eccvm, translator, merge) - bool verified = goblin.verify(proof); - EXPECT_TRUE(ultra_verified && verified); -} - -// TODO(https://github.com/AztecProtocol/barretenberg/issues/787) Expand these tests. diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 3b028be637e..fdfed9ef41d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -23,8 +23,7 @@ class Goblin { public: using Builder = GoblinUltraCircuitBuilder; using Fr = bb::fr; - using Transcript = bb::BaseTranscript; - + using Transcript = NativeTranscript; using GoblinUltraComposer = bb::UltraComposer_; using GoblinUltraVerifier = bb::UltraVerifier_; using OpQueue = bb::ECCOpQueue; @@ -35,8 +34,8 @@ class Goblin { using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder; using TranslatorComposer = bb::GoblinTranslatorComposer; using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; - using MergeProver = bb::MergeProver; - using MergeVerifier = bb::MergeVerifier; + using MergeProver = bb::MergeProver_; + using MergeVerifier = bb::MergeVerifier_; /** * @brief Output of goblin::accumulate; an Ultra proof and the corresponding verification key * @@ -105,7 +104,8 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); @@ -117,7 +117,32 @@ class Goblin { merge_proof_exists = true; } - return { ultra_proof, instance->verification_key }; + return { ultra_proof, verification_key }; + }; + + /** + * @brief Add a recursive merge verifier to input circuit and construct a merge proof for the updated op queue + * @details When this method is used, the "prover" functionality of the IVC scheme must be performed explicitly, but + * this method has to be called first so that the recursive merge verifier can be "appended" to the circuit being + * accumulated + * + * @param circuit_builder + */ + void merge(GoblinUltraCircuitBuilder& circuit_builder) + { + // Complete the circuit logic by recursively verifying previous merge proof if it exists + if (merge_proof_exists) { + RecursiveMergeVerifier merge_verifier{ &circuit_builder }; + [[maybe_unused]] auto pairing_points = merge_verifier.verify_proof(merge_proof); + } + + // Construct and store the merge proof to be recursively verified on the next call to accumulate + MergeProver merge_prover{ op_queue }; + merge_proof = merge_prover.construct_proof(); + + if (!merge_proof_exists) { + merge_proof_exists = true; + } }; /** @@ -205,11 +230,12 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); - accumulator = { ultra_proof, instance->verification_key }; + accumulator = { ultra_proof, verification_key }; // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now since we're not // mocking the first set of ecc ops diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp new file mode 100644 index 00000000000..c731722d755 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -0,0 +1,76 @@ +#include "barretenberg/goblin/goblin.hpp" +#include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/ultra_honk/ultra_composer.hpp" + +#include + +using namespace bb; + +class GoblinRecursionTests : public ::testing::Test { + protected: + static void SetUpTestSuite() + { + srs::init_crs_factory("../srs_db/ignition"); + srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); + } + + using Curve = curve::BN254; + using FF = Curve::ScalarField; + using GoblinUltraBuilder = GoblinUltraCircuitBuilder; + using KernelInput = Goblin::AccumulationOutput; + + static Goblin::AccumulationOutput construct_accumulator(GoblinUltraBuilder& builder) + { + GoblinUltraComposer composer; + auto prover_instance = composer.create_prover_instance(builder); + auto verifier_instance = composer.create_verifier_instance(prover_instance); + auto prover = composer.create_prover(prover_instance); + auto ultra_proof = prover.construct_proof(); + return { ultra_proof, verifier_instance->verification_key }; + } +}; + +/** + * @brief A full Goblin test that mimicks the basic aztec client architecture + * @details + */ +TEST_F(GoblinRecursionTests, Vanilla) +{ + Goblin goblin; + + Goblin::AccumulationOutput kernel_accum; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/723): + GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(goblin.op_queue); + + size_t NUM_CIRCUITS = 2; + for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + + // Construct and accumulate a mock function circuit + GoblinUltraCircuitBuilder function_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_arithmetic_circuit(function_circuit, 1 << 8); + GoblinMockCircuits::construct_goblin_ecc_op_circuit(function_circuit); + info("function merge"); + goblin.merge(function_circuit); + auto function_accum = construct_accumulator(function_circuit); + + // Construct and accumulate the mock kernel circuit (no kernel accum in first round) + GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; + GoblinMockCircuits::construct_mock_kernel_small(kernel_circuit, function_accum, kernel_accum); + info("kernel accum"); + goblin.merge(kernel_circuit); + kernel_accum = construct_accumulator(kernel_circuit); + } + + Goblin::Proof proof = goblin.prove(); + // Verify the final ultra proof + GoblinUltraVerifier ultra_verifier{ kernel_accum.verification_key }; + bool ultra_verified = ultra_verifier.verify_proof(kernel_accum.proof); + // Verify the goblin proof (eccvm, translator, merge) + bool verified = goblin.verify(proof); + EXPECT_TRUE(ultra_verified && verified); +} + +// TODO(https://github.com/AztecProtocol/barretenberg/issues/787) Expand these tests. diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 576fc798ae0..1091065603b 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -13,6 +13,7 @@ #include "barretenberg/stdlib/merkle_tree/merkle_tree.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" namespace bb { @@ -29,6 +30,9 @@ class GoblinMockCircuits { using RecursiveFlavor = bb::GoblinUltraRecursiveFlavor_; using RecursiveVerifier = bb::stdlib::recursion::honk::UltraRecursiveVerifier_; using KernelInput = Goblin::AccumulationOutput; + using VerifierInstance = bb::VerifierInstance_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; + using RecursiveVerifierAccumulator = std::shared_ptr; static constexpr size_t NUM_OP_QUEUE_COLUMNS = Flavor::NUM_WIRES; /** @@ -164,7 +168,7 @@ class GoblinMockCircuits { } /** - * @brief Construct a mock kernel circuit + * @brief Construct a size 2^17 mock kernel circuit based on vanilla recursion for benchmarking * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive * verification of a function circuit proof, and optionally (3) recursive verification of a previous kernel circuit * proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of the kernel to 2^17. @@ -174,9 +178,9 @@ class GoblinMockCircuits { * @param function_accum {proof, vkey} for function circuit to be recursively verified * @param prev_kernel_accum {proof, vkey} for previous kernel circuit to be recursively verified */ - static void construct_mock_kernel_circuit(GoblinUltraBuilder& builder, - const KernelInput& function_accum, - const KernelInput& prev_kernel_accum) + static void construct_mock_recursion_kernel_circuit(GoblinUltraBuilder& builder, + const KernelInput& function_accum, + const KernelInput& prev_kernel_accum) { // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make the // kernel "full" within the dyadic size 2^17 (130914 gates) @@ -191,6 +195,68 @@ class GoblinMockCircuits { RecursiveVerifier verifier1{ &builder, function_accum.verification_key }; verifier1.verify_proof(function_accum.proof); + // Execute recursive aggregation of previous kernel proof if one exists + if (!prev_kernel_accum.proof.empty()) { + RecursiveVerifier verifier2{ &builder, prev_kernel_accum.verification_key }; + verifier2.verify_proof(prev_kernel_accum.proof); + } + info(builder.get_num_gates()); + } + + /** + * @brief Construct a mock kernel circuit based on folding + * @details This circuit contains (1) some arbitrary operations representing general kernel logic, (2) recursive + * folding verification of a function circuit folding proof, and (3) recursive folding verification of a previous + * kernel circuit folding proof. The arbitrary kernel logic is structured to bring the final dyadic circuit size of + * the kernel to 2^17. + * + * @param builder + * @param function_fold_proof + * @param kernel_fold_proof + */ + static std::shared_ptr construct_mock_folding_kernel( + GoblinUltraBuilder& builder, + const std::vector& fold_proof_1, + const std::vector& fold_proof_2, + std::shared_ptr& verifier_inst_1, + std::shared_ptr& verifier_inst_2, + std::shared_ptr& prev_kernel_accum) + { + using GURecursiveFlavor = GoblinUltraRecursiveFlavor_; + using RecursiveVerifierInstances = + bb::stdlib::recursion::honk::RecursiveVerifierInstances_; + using FoldingRecursiveVerifier = + bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + + // Add operations representing general kernel logic e.g. state updates. Note: these are structured to make + // the kernel "full" within the dyadic size 2^17 (130914 gates) + const size_t NUM_MERKLE_CHECKS = 35; + const size_t NUM_ECDSA_VERIFICATIONS = 1; + const size_t NUM_SHA_HASHES = 1; + stdlib::generate_merkle_membership_test_circuit(builder, NUM_MERKLE_CHECKS); + stdlib::generate_ecdsa_verification_test_circuit(builder, NUM_ECDSA_VERIFICATIONS); + stdlib::generate_sha256_test_circuit(builder, NUM_SHA_HASHES); + + FoldingRecursiveVerifier verifier_1{ &builder, prev_kernel_accum, { verifier_inst_1->verification_key } }; + auto fctn_verifier_accum = verifier_1.verify_folding_proof(fold_proof_1); + auto native_acc = std::make_shared(fctn_verifier_accum->get_value()); + FoldingRecursiveVerifier verifier_2{ &builder, native_acc, { verifier_inst_2->verification_key } }; + auto kernel_verifier_accum = verifier_2.verify_folding_proof(fold_proof_2); + return std::make_shared(kernel_verifier_accum->get_value()); + } + + /** + * @brief A minimal version of the mock kernel (recursive verifiers only) for faster testing + * + */ + static void construct_mock_kernel_small(GoblinUltraBuilder& builder, + const KernelInput& function_accum, + const KernelInput& prev_kernel_accum) + { + // Execute recursive aggregation of function proof + RecursiveVerifier verifier1{ &builder, function_accum.verification_key }; + verifier1.verify_proof(function_accum.proof); + // Execute recursive aggregation of previous kernel proof if one exists if (!prev_kernel_accum.proof.empty()) { RecursiveVerifier verifier2{ &builder, prev_kernel_accum.verification_key }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp index 6d642bf5bc8..db0fc69b80d 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -23,7 +23,7 @@ TEST_F(MockCircuits, PinFunctionSizes) GoblinUltraCircuitBuilder app_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); GoblinUltraComposer composer; - auto instance = composer.create_instance(app_circuit); + auto instance = composer.create_prover_instance(app_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 19); } else { @@ -34,7 +34,7 @@ TEST_F(MockCircuits, PinFunctionSizes) run_test(false); } -TEST_F(MockCircuits, PinKernelSizes) +TEST_F(MockCircuits, PinRecursionKernelSizes) { const auto run_test = [](bool large) { { @@ -45,9 +45,9 @@ TEST_F(MockCircuits, PinKernelSizes) GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); auto function_accum = goblin.accumulate(app_circuit); GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_mock_kernel_circuit(kernel_circuit, function_accum, kernel_accum); + GoblinMockCircuits::construct_mock_recursion_kernel_circuit(kernel_circuit, function_accum, kernel_accum); GoblinUltraComposer composer; - auto instance = composer.create_instance(kernel_circuit); + auto instance = composer.create_prover_instance(kernel_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } else { diff --git a/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp b/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp index 091d310d5c2..a20111a69be 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/types/proof.hpp @@ -1,9 +1,12 @@ #pragma once #include "barretenberg/ecc/curves/bn254/fr.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" #include namespace bb { -using HonkProof = std::vector; +using HonkProof = std::vector; // this can be fr? -} // namespace bb \ No newline at end of file +template using StdlibProof = std::vector>; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp index 7f01159e95c..9dbe3cd4d49 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp @@ -19,13 +19,13 @@ template class ProverBase { ProverBase& operator=(const ProverBase& other) = delete; ProverBase& operator=(ProverBase&& other); - BBERG_PROFILE void execute_preamble_round(); - BBERG_PROFILE void execute_first_round(); - BBERG_PROFILE void execute_second_round(); - BBERG_PROFILE void execute_third_round(); - BBERG_PROFILE void execute_fourth_round(); - BBERG_PROFILE void execute_fifth_round(); - BBERG_PROFILE void execute_sixth_round(); + BB_PROFILE void execute_preamble_round(); + BB_PROFILE void execute_first_round(); + BB_PROFILE void execute_second_round(); + BB_PROFILE void execute_third_round(); + BB_PROFILE void execute_fourth_round(); + BB_PROFILE void execute_fifth_round(); + BB_PROFILE void execute_sixth_round(); void add_polynomial_evaluations_to_transcript(); void compute_batch_opening_polynomials(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index 5bdf8b3faab..a5110aefa35 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -1,5 +1,6 @@ #pragma once #include "barretenberg/ecc/curves/bn254/bn254.hpp" +#include "barretenberg/proof_system/types/circuit_type.hpp" #include #include #include @@ -30,8 +31,8 @@ namespace bb { * We should only do this if it becomes necessary or convenient. */ -// These are not magic numbers and they should not be written with global constants. These parameters are not accessible -// through clearly named static class members. +// These are not magic numbers and they should not be written with global constants. These parameters are not +// accessible through clearly named static class members. template class StandardArith { public: static constexpr size_t NUM_WIRES = 3; @@ -114,13 +115,6 @@ template class UltraArith { } } - /** - * @brief Add zeros to all selectors which are not part of the conventional Ultra arithmetization - * @details Does nothing for this class since this IS the conventional Ultra arithmetization - * - */ - void pad_additional(){}; - // Note: These are needed for Plonk only (for poly storage in a std::map). Must be in same order as above struct. inline static const std::vector selector_names = { "q_m", "q_c", "q_1", "q_2", "q_3", "q_4", "q_arith", "q_sort", @@ -196,6 +190,19 @@ template class UltraHonkArith { q_poseidon2_internal().emplace_back(0); }; + /** + * @brief Resizes all selectors which are not part of the conventional Ultra arithmetization + * @details Facilitates reuse of Ultra gate construction functions in arithmetizations which extend the conventional + * Ultra arithmetization + * @param new_size + */ + void resize_additional(size_t new_size) + { + q_busread().resize(new_size); + q_poseidon2_external().resize(new_size); + q_poseidon2_internal().resize(new_size); + }; + // Note: Unused. Needed only for consistency with Ultra arith (which is used by Plonk) inline static const std::vector selector_names = {}; }; @@ -205,4 +212,7 @@ class GoblinTranslatorArith { static constexpr size_t NUM_WIRES = 81; static constexpr size_t NUM_SELECTORS = 0; }; + +template +concept HasAdditionalSelectors = IsAnyOf>; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index c2630db7b7b..e4181fecc6b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -60,6 +60,7 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ this->q_busread().emplace_back(0); this->q_poseidon2_external().emplace_back(1); this->q_poseidon2_internal().emplace_back(1); + this->check_selector_length_consistency(); ++this->num_gates; @@ -82,6 +83,7 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ this->q_busread().emplace_back(0); this->q_poseidon2_external().emplace_back(0); this->q_poseidon2_internal().emplace_back(0); + this->check_selector_length_consistency(); ++this->num_gates; } @@ -255,6 +257,7 @@ void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_l this->q_aux().emplace_back(0); this->q_poseidon2_external().emplace_back(0); this->q_poseidon2_internal().emplace_back(0); + this->check_selector_length_consistency(); ++this->num_gates; } @@ -283,6 +286,7 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid this->q_busread().emplace_back(0); this->q_poseidon2_external().emplace_back(1); this->q_poseidon2_internal().emplace_back(0); + this->check_selector_length_consistency(); ++this->num_gates; } @@ -310,6 +314,7 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid this->q_busread().emplace_back(0); this->q_poseidon2_external().emplace_back(0); this->q_poseidon2_internal().emplace_back(1); + this->check_selector_length_consistency(); ++this->num_gates; } @@ -340,6 +345,7 @@ template void GoblinUltraCircuitBuilder_::create_poseidon2_end this->q_busread().emplace_back(0); this->q_poseidon2_external().emplace_back(0); this->q_poseidon2_internal().emplace_back(0); + this->check_selector_length_consistency(); ++this->num_gates; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp index 28a6959b830..21aa754edfe 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.cpp @@ -77,7 +77,9 @@ void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_no q_lookup_type().emplace_back(0); q_elliptic().emplace_back(1); q_aux().emplace_back(1); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; @@ -138,7 +140,9 @@ void UltraCircuitBuilder_::create_add_gate(const add_triple_) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -171,7 +175,9 @@ void UltraCircuitBuilder_::create_big_add_gate(const add_quad_< q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -266,7 +272,9 @@ void UltraCircuitBuilder_::create_big_mul_gate(const mul_quad_< q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -293,7 +301,9 @@ void UltraCircuitBuilder_::create_balanced_add_gate(const add_q q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; // Why 3? TODO: return to this @@ -336,7 +346,9 @@ void UltraCircuitBuilder_::create_mul_gate(const mul_triple_) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -366,7 +378,9 @@ void UltraCircuitBuilder_::create_bool_gate(const uint32_t vari q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -398,7 +412,9 @@ void UltraCircuitBuilder_::create_poly_gate(const poly_triple_< q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -453,7 +469,9 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga q_lookup_type().emplace_back(0); q_elliptic().emplace_back(1); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -472,7 +490,9 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -519,7 +539,9 @@ void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_ga q_sort().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -539,7 +561,9 @@ void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_ga q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -570,7 +594,9 @@ void UltraCircuitBuilder_::fix_witness(const uint32_t witness_i q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -646,7 +672,9 @@ plookup::ReadData UltraCircuitBuilder_::create_gates_ q_sort().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); ++this->num_gates; } @@ -956,7 +984,9 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } // dummy gate needed because of sort widget's check of next row @@ -976,7 +1006,9 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } @@ -1011,7 +1043,9 @@ void UltraCircuitBuilder_::create_dummy_constraints(const std:: q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } } @@ -1043,7 +1077,9 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); // enforce range check for middle rows for (size_t i = gate_width; i < variable_index.size() - gate_width; i += gate_width) { @@ -1064,7 +1100,9 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } // enforce range checks of last row and ending at end @@ -1085,7 +1123,9 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } @@ -1107,7 +1147,9 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( q_elliptic().emplace_back(0); q_lookup_type().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); } @@ -1224,7 +1266,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1236,7 +1280,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(1); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1248,7 +1294,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1260,7 +1308,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1272,7 +1322,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(1); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1288,7 +1340,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1305,7 +1359,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(1); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1319,7 +1375,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1334,7 +1392,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(1); // validate record witness is correctly computed q_c().emplace_back(0); // read/write flag stored in q_c q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1349,7 +1409,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(1); // validate record witness is correctly computed q_c().emplace_back(0); // read/write flag stored in q_c q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1364,7 +1426,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(1); // validate record witness is correctly computed q_c().emplace_back(1); // read/write flag stored in q_c q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1376,7 +1440,9 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT q_m().emplace_back(0); q_c().emplace_back(0); q_arith().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } check_selector_length_consistency(); break; } @@ -1898,7 +1964,9 @@ std::array UltraCircuitBuilder_::evaluate_non_nati q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } } check_selector_length_consistency(); @@ -2021,7 +2089,9 @@ std::array UltraCircuitBuilder_::evaluate_non_nati q_lookup_type().emplace_back(0); q_elliptic().emplace_back(0); q_aux().emplace_back(0); - selectors.pad_additional(); + if constexpr (HasAdditionalSelectors) { + selectors.pad_additional(); + } } check_selector_length_consistency(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index 055db48379d..78242840d9c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -458,6 +458,9 @@ class UltraCircuitBuilder_ : public CircuitBuilderBaseq_elliptic().resize(num_gates); builder->q_aux().resize(num_gates); builder->q_lookup_type().resize(num_gates); + if constexpr (HasAdditionalSelectors) { + builder->selectors.resize_additional(num_gates); + } } /** * @brief Checks that the circuit state is the same as the stored circuit's one diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp index 51d55e9766a..ccac06c7928 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -20,51 +20,6 @@ DeciderProver_::DeciderProver_(const std::shared_ptr& inst, , commitment_key(commitment_key) {} -/** - * @brief Add ϕ, \vec{β}, e to the transcript. These are produced in the last round of folding that was carried out - * before deciding. - */ -template void DeciderProver_::execute_preamble_round() -{ - const auto accumulator_size = static_cast(accumulator->instance_size); - const auto num_public_inputs = static_cast(accumulator->public_inputs.size()); - transcript->send_to_verifier("accumulator_size", accumulator_size); - transcript->send_to_verifier("public_input_size", num_public_inputs); - - for (size_t i = 0; i < accumulator->public_inputs.size(); ++i) { - auto public_input_i = accumulator->public_inputs[i]; - transcript->send_to_verifier("public_input_" + std::to_string(i), public_input_i); - } - - transcript->send_to_verifier("eta", accumulator->relation_parameters.eta); - transcript->send_to_verifier("beta", accumulator->relation_parameters.beta); - transcript->send_to_verifier("gamma", accumulator->relation_parameters.gamma); - transcript->send_to_verifier("public_input_delta", accumulator->relation_parameters.public_input_delta); - transcript->send_to_verifier("lookup_grand_product_delta", - accumulator->relation_parameters.lookup_grand_product_delta); - size_t alpha_idx = 0; - for (auto alpha : accumulator->alphas) { - transcript->send_to_verifier("alpha_" + std::to_string(alpha_idx), alpha); - } - - transcript->send_to_verifier("target_sum", accumulator->target_sum); - for (size_t idx = 0; idx < accumulator->gate_challenges.size(); idx++) { - transcript->send_to_verifier("gate_challenge_" + std::to_string(idx), accumulator->gate_challenges[idx]); - } - - auto comm_view = accumulator->witness_commitments.get_all(); - auto witness_labels = accumulator->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - transcript->send_to_verifier(witness_labels[idx], comm_view[idx]); - } - - auto vk_view = accumulator->verification_key->get_all(); - auto vk_labels = accumulator->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - transcript->send_to_verifier(vk_labels[idx], vk_view[idx]); - } -} - /** * @brief Run Sumcheck to establish that ∑_i pow(\vec{β*})f_i(ω) = e*. This results in u = (u_1,...,u_d) sumcheck round * challenges and all evaluations at u being calculated. @@ -102,9 +57,6 @@ template HonkProof& DeciderProver_::export_proof( template HonkProof& DeciderProver_::construct_proof() { - // Add ϕ, \vec{β*}, e* to transcript - execute_preamble_round(); - // Run sumcheck subprotocol. execute_relation_check_rounds(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp index 68440d5129b..43d0b602bcc 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -28,9 +28,9 @@ template class DeciderProver_ { const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); - BBERG_PROFILE void execute_preamble_round(); - BBERG_PROFILE void execute_relation_check_rounds(); - BBERG_PROFILE void execute_zeromorph_rounds(); + BB_PROFILE void execute_preamble_round(); + BB_PROFILE void execute_relation_check_rounds(); + BB_PROFILE void execute_zeromorph_rounds(); HonkProof& export_proof(); HonkProof& construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 1c6601613fb..197d739817e 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -8,8 +8,8 @@ namespace bb { template DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& verifier_key) - : key(verifier_key) + const std::shared_ptr& accumulator) + : accumulator(accumulator) , transcript(transcript) {} template @@ -25,68 +25,69 @@ DeciderVerifier_::DeciderVerifier_() */ template bool DeciderVerifier_::verify_proof(const HonkProof& proof) { - using FF = typename Flavor::FF; - using Commitment = typename Flavor::Commitment; + // using FF = typename Flavor::FF; + // using Commitment = typename Flavor::Commitment; using Curve = typename Flavor::Curve; using ZeroMorph = ZeroMorphVerifier_; - using Instance = VerifierInstance_; + // using Instance = VerifierInstance_; using VerifierCommitments = typename Flavor::VerifierCommitments; - static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; + // static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; transcript = std::make_shared(proof); - auto inst = std::make_unique(); - - inst->instance_size = transcript->template receive_from_prover("instance_size"); - inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); - inst->public_input_size = transcript->template receive_from_prover("public_input_size"); - - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - auto eta = transcript->template receive_from_prover("eta"); - auto beta = transcript->template receive_from_prover("beta"); - auto gamma = transcript->template receive_from_prover("gamma"); - auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); - auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - - inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover("target_sum"); - - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); - } - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); - } - - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); - } - - VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; - - auto sumcheck = SumcheckVerifier(inst->log_instance_size, transcript, inst->target_sum); + // auto inst = std::make_unique(); + + // inst->instance_size = transcript->template receive_from_prover("instance_size"); + // inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); + // inst->public_input_size = transcript->template receive_from_prover("public_input_size"); + + // for (size_t i = 0; i < inst->public_input_size; ++i) { + // auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); + // inst->public_inputs.emplace_back(public_input_i); + // } + + // auto eta = transcript->template receive_from_prover("eta"); + // auto beta = transcript->template receive_from_prover("beta"); + // auto gamma = transcript->template receive_from_prover("gamma"); + // auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); + // auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); + // inst->relation_parameters = + // RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + + // for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { + + // inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); + // } + + // inst->target_sum = transcript->template receive_from_prover("target_sum"); + + // inst->gate_challenges = std::vector(inst->log_instance_size); + // for (size_t idx = 0; idx < inst->log_instance_size; idx++) { + // inst->gate_challenges[idx] = + // transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); + // } + // auto comm_view = inst->witness_commitments.get_all(); + // auto witness_labels = inst->commitment_labels.get_witness(); + // for (size_t idx = 0; idx < witness_labels.size(); idx++) { + // comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); + // } + + // inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); + // auto vk_view = inst->verification_key->get_all(); + // auto vk_labels = inst->commitment_labels.get_precomputed(); + // for (size_t idx = 0; idx < vk_labels.size(); idx++) { + // vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); + // } + + VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; + + auto sumcheck = SumcheckVerifier(accumulator->log_instance_size, transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); // If Sumcheck did not verify, return false if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { + info("here"); return false; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp index 70ca2033617..3969b89d96c 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp @@ -3,6 +3,7 @@ #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/srs/global_crs.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" namespace bb { @@ -12,16 +13,18 @@ template class DeciderVerifier_ { using VerificationKey = typename Flavor::VerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using Transcript = typename Flavor::Transcript; + using VerifierInstance = VerifierInstance_; public: explicit DeciderVerifier_(); explicit DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& verifier_key = nullptr); + const std::shared_ptr& accumulator = nullptr); bool verify_proof(const HonkProof& proof); std::shared_ptr key; std::map commitments; + std::shared_ptr accumulator; std::shared_ptr pcs_verification_key; std::shared_ptr transcript; }; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index c0efde0a3d8..98930e72646 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -55,7 +55,7 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared instance->witness_commitments.calldata_read_counts); } - auto eta = transcript->get_challenge(domain_separator + "_eta"); + auto eta = transcript->template get_challenge(domain_separator + "_eta"); instance->compute_sorted_accumulator_polynomials(eta); // Commit to the sorted withness-table accumulator and the finalized (i.e. with memory records) fourth wire @@ -67,7 +67,8 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared witness_commitments.sorted_accum); transcript->send_to_verifier(domain_separator + "_" + commitment_labels.w_4, witness_commitments.w_4); - auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + auto [beta, gamma] = + transcript->template get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); if constexpr (IsGoblinFlavor) { // Compute and commit to the logderivative inverse used in DataBus @@ -88,75 +89,78 @@ void ProtoGalaxyProver_::finalise_and_send_instance(std::shared transcript->send_to_verifier(domain_separator + "_" + commitment_labels.z_lookup, instance->witness_commitments.z_lookup); for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - instance->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); - } - auto vk_view = instance->verification_key->get_all(); - auto labels = instance->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + labels[idx], vk_view[idx]); + instance->alphas[idx] = + transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } + // auto vk_view = instance->verification_key->get_all(); + // auto labels = instance->commitment_labels.get_precomputed(); + // for (size_t idx = 0; idx < labels.size(); idx++) { + // transcript->send_to_verifier(domain_separator + "_" + labels[idx], vk_view[idx]); + // } } -template -void ProtoGalaxyProver_::send_accumulator(std::shared_ptr instance, - const std::string& domain_separator) -{ - const auto instance_size = static_cast(instance->instance_size); - const auto num_public_inputs = static_cast(instance->public_inputs.size()); - transcript->send_to_verifier(domain_separator + "_instance_size", instance_size); - transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); - - for (size_t i = 0; i < instance->public_inputs.size(); ++i) { - auto public_input_i = instance->public_inputs[i]; - transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); - } - - transcript->send_to_verifier(domain_separator + "_eta", instance->relation_parameters.eta); - transcript->send_to_verifier(domain_separator + "_beta", instance->relation_parameters.beta); - transcript->send_to_verifier(domain_separator + "_gamma", instance->relation_parameters.gamma); - transcript->send_to_verifier(domain_separator + "_public_input_delta", - instance->relation_parameters.public_input_delta); - transcript->send_to_verifier(domain_separator + "_lookup_grand_product_delta", - instance->relation_parameters.lookup_grand_product_delta); - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - transcript->send_to_verifier(domain_separator + "_alpha_" + std::to_string(idx), instance->alphas[idx]); - } - - transcript->send_to_verifier(domain_separator + "_target_sum", instance->target_sum); - for (size_t idx = 0; idx < instance->gate_challenges.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_gate_challenge_" + std::to_string(idx), - instance->gate_challenges[idx]); - } - - auto comm_view = instance->witness_commitments.get_all(); - auto witness_labels = instance->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + witness_labels[idx], comm_view[idx]); - } - - auto vk_view = instance->verification_key->get_all(); - auto vk_labels = instance->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - transcript->send_to_verifier(domain_separator + "_" + vk_labels[idx], vk_view[idx]); - } -} +// template +// void ProtoGalaxyProver_::send_accumulator(std::shared_ptr instance, +// const std::string& domain_separator) +// { +// const auto instance_size = static_cast(instance->instance_size); +// const auto num_public_inputs = static_cast(instance->public_inputs.size()); +// transcript->send_to_verifier(domain_separator + "_instance_size", instance_size); +// transcript->send_to_verifier(domain_separator + "_public_input_size", num_public_inputs); + +// for (size_t i = 0; i < instance->public_inputs.size(); ++i) { +// auto public_input_i = instance->public_inputs[i]; +// transcript->send_to_verifier(domain_separator + "_public_input_" + std::to_string(i), public_input_i); +// } + +// transcript->send_to_verifier(domain_separator + "_eta", instance->relation_parameters.eta); +// transcript->send_to_verifier(domain_separator + "_beta", instance->relation_parameters.beta); +// transcript->send_to_verifier(domain_separator + "_gamma", instance->relation_parameters.gamma); +// transcript->send_to_verifier(domain_separator + "_public_input_delta", +// instance->relation_parameters.public_input_delta); +// transcript->send_to_verifier(domain_separator + "_lookup_grand_product_delta", +// instance->relation_parameters.lookup_grand_product_delta); + +// for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { +// transcript->send_to_verifier(domain_separator + "_alpha_" + std::to_string(idx), instance->alphas[idx]); +// } + +// transcript->send_to_verifier(domain_separator + "_target_sum", instance->target_sum); +// for (size_t idx = 0; idx < instance->gate_challenges.size(); idx++) { +// transcript->send_to_verifier(domain_separator + "_gate_challenge_" + std::to_string(idx), +// instance->gate_challenges[idx]); +// } + +// auto comm_view = instance->witness_commitments.get_all(); +// auto witness_labels = instance->commitment_labels.get_witness(); +// for (size_t idx = 0; idx < witness_labels.size(); idx++) { +// transcript->send_to_verifier(domain_separator + "_" + witness_labels[idx], comm_view[idx]); +// } + +// auto vk_view = instance->verification_key->get_all(); +// auto vk_labels = instance->commitment_labels.get_precomputed(); +// for (size_t idx = 0; idx < vk_labels.size(); idx++) { +// transcript->send_to_verifier(domain_separator + "_" + vk_labels[idx], vk_view[idx]); +// } +// } template void ProtoGalaxyProver_::prepare_for_folding() { auto idx = 0; auto instance = instances[0]; auto domain_separator = std::to_string(idx); - transcript->send_to_verifier(domain_separator + "is_accumulator", instance->is_accumulator); - if (instance->is_accumulator) { - send_accumulator(instance, domain_separator); - } else { + // transcript->send_to_verifier(domain_separator + "is_accumulator", instance->is_accumulator); + if (!instance->is_accumulator) + // { + // send_accumulator(instance, domain_separator); + // }else + { // This is the first round of folding and we need to generate some gate challenges. // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more // efficient by avoiding the computation of the perturbator finalise_and_send_instance(instance, domain_separator); instance->target_sum = 0; - auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + auto beta = transcript->template get_challenge(domain_separator + "_initial_gate_challenge"); std::vector gate_challenges(instance->log_instance_size); gate_challenges[0] = beta; for (size_t i = 1; i < instance->log_instance_size; i++) { @@ -198,10 +202,6 @@ std::shared_ptr ProtoGalaxyProver_send_to_verifier("next_target_sum", next_target_sum); - for (size_t idx = 0; idx < instances.next_gate_challenges.size(); idx++) { - transcript->send_to_verifier("next_gate_challenge_" + std::to_string(idx), instances.next_gate_challenges[idx]); - } next_accumulator->target_sum = next_target_sum; next_accumulator->gate_challenges = instances.next_gate_challenges; @@ -223,20 +223,6 @@ std::shared_ptr ProtoGalaxyProver_prover_polynomials = std::move(acc_prover_polynomials); - // Fold the witness commtiments and send them to the verifier - auto witness_labels = next_accumulator->commitment_labels.get_witness(); - size_t comm_idx = 0; - for (auto& acc_comm : next_accumulator->witness_commitments.get_all()) { - acc_comm = Commitment::infinity(); - size_t inst_idx = 0; - for (auto& instance : instances) { - acc_comm = acc_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst_idx]; - inst_idx++; - } - transcript->send_to_verifier("next_" + witness_labels[comm_idx], acc_comm); - comm_idx++; - } - // Fold public data ϕ from all instances to produce ϕ* and add it to the transcript. As part of the folding // verification, the verifier will produce ϕ* as well and check it against what was sent by the prover. @@ -246,10 +232,12 @@ std::shared_ptr ProtoGalaxyProver_public_inputs) { size_t inst = 0; for (auto& instance : instances) { - el += instance->public_inputs[el_idx] * lagranges[inst]; - inst++; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/830) + if (instance->public_inputs.size() >= next_accumulator->public_inputs.size()) { + el += instance->public_inputs[el_idx] * lagranges[inst]; + inst++; + }; } - transcript->send_to_verifier("next_public_input_" + std::to_string(el_idx), el); el_idx++; } @@ -258,7 +246,6 @@ std::shared_ptr ProtoGalaxyProver_alphas; for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { folded_alphas[idx] = instances.alphas[idx].evaluate(challenge); - transcript->send_to_verifier("next_alpha_" + std::to_string(idx), folded_alphas[idx]); } // Evaluate each relation parameter univariate at challenge to obtain the folded relation parameters and send to @@ -271,32 +258,7 @@ std::shared_ptr ProtoGalaxyProver_send_to_verifier("next_eta", folded_relation_parameters.eta); - transcript->send_to_verifier("next_beta", folded_relation_parameters.beta); - transcript->send_to_verifier("next_gamma", folded_relation_parameters.gamma); - transcript->send_to_verifier("next_public_input_delta", folded_relation_parameters.public_input_delta); - transcript->send_to_verifier("next_lookup_grand_product_delta", - folded_relation_parameters.lookup_grand_product_delta); next_accumulator->relation_parameters = folded_relation_parameters; - - // Fold the verification key and send it to the verifier as this is part of ϕ as well - auto acc_vk = std::make_shared(instances[0]->prover_polynomials.get_polynomial_size(), - instances[0]->public_inputs.size()); - auto labels = next_accumulator->commitment_labels.get_precomputed(); - size_t vk_idx = 0; - for (auto& vk : acc_vk->get_all()) { - size_t inst = 0; - vk = Commitment::infinity(); - for (auto& instance : instances) { - vk = vk + (instance->verification_key->get_all()[vk_idx]) * lagranges[inst]; - inst++; - } - transcript->send_to_verifier("next_" + labels[vk_idx], vk); - vk_idx++; - } - next_accumulator->verification_key = acc_vk; return next_accumulator; } @@ -304,16 +266,17 @@ template FoldingResult ProtoGalaxyProver_::fold_instances() { prepare_for_folding(); - FF delta = transcript->get_challenge("delta"); + FF delta = transcript->template get_challenge("delta"); auto accumulator = get_accumulator(); auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); auto perturbator = compute_perturbator(accumulator, deltas); - for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + + for (size_t idx = 1; idx <= accumulator->log_instance_size; idx++) { transcript->send_to_verifier("perturbator_" + std::to_string(idx), perturbator[idx]); } - auto perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + auto perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); instances.next_gate_challenges = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); combine_relation_parameters(instances); @@ -327,7 +290,7 @@ FoldingResult ProtoGalaxyProver_send_to_verifier("combiner_quotient_" + std::to_string(idx), combiner_quotient.value_at(idx)); } - FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); + FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); FoldingResult res; auto next_accumulator = diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 026c83a618c..a566f399955 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -28,6 +28,7 @@ template class ProtoGalaxyProver_ { using VerificationKey = typename Flavor::VerificationKey; using CommitmentKey = typename Flavor::CommitmentKey; using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; using Commitment = typename Flavor::Commitment; using BaseUnivariate = Univariate; @@ -73,7 +74,7 @@ template class ProtoGalaxyProver_ { * @param domain_separator separates the same type of data coming from difference instances by instance * index */ - void send_accumulator(std::shared_ptr, const std::string& domain_separator); + // void send_accumulator(std::shared_ptr, const std::string& domain_separator); /** * @brief For each instance produced by a circuit, prior to folding, we need to complete the computation of its @@ -91,7 +92,7 @@ template class ProtoGalaxyProver_ { * * TODO(https://github.com/AztecProtocol/barretenberg/issues/753): fold goblin polynomials */ - BBERG_PROFILE FoldingResult fold_instances(); + BB_PROFILE FoldingResult fold_instances(); /** * @brief For a new round challenge δ at each iteration of the ProtoGalaxy protocol, compute the vector diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index bee65a68010..818c02ca7d5 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -2,65 +2,6 @@ #include "barretenberg/proof_system/library/grand_product_delta.hpp" namespace bb { -template -void ProtoGalaxyVerifier_::receive_accumulator(const std::shared_ptr& inst, - const std::string& domain_separator) -{ - // Get circuit parameters - inst->instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); - inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); - inst->public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - - // Get folded public inputs - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = - transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - // Get folded relation parameters - auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); - auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); - auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); - auto public_input_delta = transcript->template receive_from_prover(domain_separator + "_public_input_delta"); - auto lookup_grand_product_delta = - transcript->template receive_from_prover(domain_separator + "_lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - // Get the folded relation separator challenges \vec{α} - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = - transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); - - // Get the folded gate challenges, \vec{β} in the paper - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); - } - - // Get the folded commitments to all witness polynomials - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = - transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); - } - - // Get the folded commitments to selector polynomials - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } -} - template void ProtoGalaxyVerifier_::receive_and_finalise_instance(const std::shared_ptr& inst, const std::string& domain_separator) @@ -104,13 +45,14 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons } // Get challenge for sorted list batching and wire four memory records commitment - auto eta = transcript->get_challenge(domain_separator + "_eta"); + auto eta = transcript->template get_challenge(domain_separator + "_eta"); witness_commitments.sorted_accum = transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); // Get permutation challenges and commitment to permutation and lookup grand products - auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + auto [beta, gamma] = + transcript->template get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); if constexpr (IsGoblinFlavor) { // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial @@ -132,15 +74,7 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); - } - - // Get the commitments to the selector polynomials for the given instance - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); + inst->alphas[idx] = transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } } @@ -153,16 +87,16 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec auto index = 0; auto inst = instances[0]; auto domain_separator = std::to_string(index); - inst->is_accumulator = transcript->template receive_from_prover(domain_separator + "is_accumulator"); - if (inst->is_accumulator) { - receive_accumulator(inst, domain_separator); - } else { + // auto is_accumulator = transcript->template receive_from_prover(domain_separator + "is_accumulator"); + if (!inst->is_accumulator) { + // receive_accumulator(inst, domain_separator); + // } else { // This is the first round of folding and we need to generate some gate challenges. // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more // efficient by avoiding the computation of the perturbator receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; - auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + auto beta = transcript->template get_challenge(domain_separator + "_initial_gate_challenge"); std::vector gate_challenges(inst->log_instance_size); gate_challenges[0] = beta; for (size_t i = 1; i < inst->log_instance_size; i++) { @@ -180,25 +114,23 @@ void ProtoGalaxyVerifier_::prepare_for_folding(const std::vec } template -bool ProtoGalaxyVerifier_::verify_folding_proof(const std::vector& fold_data) +std::shared_ptr ProtoGalaxyVerifier_::verify_folding_proof( + const std::vector& fold_data) { prepare_for_folding(fold_data); - auto delta = transcript->get_challenge("delta"); + auto delta = transcript->template get_challenge("delta"); auto accumulator = get_accumulator(); auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); std::vector perturbator_coeffs(accumulator->log_instance_size + 1); - for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + for (size_t idx = 1; idx <= accumulator->log_instance_size; idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } - if (perturbator_coeffs[0] != accumulator->target_sum) { - return false; - } - + perturbator_coeffs[0] = accumulator->target_sum; auto perturbator = Polynomial(perturbator_coeffs); - FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + FF perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); auto perturbator_at_challenge = perturbator.evaluate(perturbator_challenge); // The degree of K(X) is dk - k - 1 = k(d - 1) - 1. Hence we need k(d - 1) evaluations to represent it. @@ -209,63 +141,62 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve } Univariate combiner_quotient( combiner_quotient_evals); - FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); + FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); auto lagranges = std::vector{ FF(1) - combiner_challenge, combiner_challenge }; + auto next_accumulator = std::make_shared(); + next_accumulator->instance_size = accumulator->instance_size; + next_accumulator->log_instance_size = accumulator->log_instance_size; + next_accumulator->is_accumulator = true; // Compute next folding parameters and verify against the ones received from the prover - auto expected_next_target_sum = + next_accumulator->target_sum = perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - auto next_target_sum = transcript->template receive_from_prover("next_target_sum"); - bool verified = (expected_next_target_sum == next_target_sum); - auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { - auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); - verified = verified & (expected_betas_star[idx] == beta_star); - } + next_accumulator->gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); // Compute ϕ and verify against the data received from the prover - WitnessCommitments acc_witness_commitments; + auto& acc_witness_commitments = next_accumulator->witness_commitments; auto witness_labels = commitment_labels.get_witness(); size_t comm_idx = 0; - for (auto& expected_comm : acc_witness_commitments.get_all()) { - expected_comm = Commitment::infinity(); + for (auto& comm : acc_witness_commitments.get_all()) { + comm = Commitment::infinity(); size_t inst = 0; for (auto& instance : instances) { - expected_comm = expected_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; + comm = comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; inst++; } - auto comm = transcript->template receive_from_prover("next_" + witness_labels[comm_idx]); - verified = verified & (comm == expected_comm); comm_idx++; } - std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); - size_t el_idx = 0; - for (auto& expected_el : folded_public_inputs) { + next_accumulator->public_input_size = instances[0]->public_input_size; + next_accumulator->public_inputs = std::vector(next_accumulator->public_input_size, 0); + size_t public_input_idx = 0; + for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; for (auto& instance : instances) { - expected_el += instance->public_inputs[el_idx] * lagranges[inst]; - inst++; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/830) + if (instance->public_inputs.size() >= next_accumulator->public_input_size) { + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; + inst++; + } } - auto el = transcript->template receive_from_prover("next_public_input" + std::to_string(el_idx)); - verified = verified & (el == expected_el); - el_idx++; + public_input_idx++; } - for (size_t alpha_idx = 0; alpha_idx < NUM_SUBRELATIONS - 1; alpha_idx++) { - FF alpha(0); + size_t alpha_idx = 0; + for (auto& alpha : next_accumulator->alphas) { + alpha = FF(0); size_t instance_idx = 0; for (auto& instance : instances) { alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; instance_idx++; } - auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); - verified = verified & (alpha == next_alpha); + alpha_idx++; } - auto expected_parameters = bb::RelationParameters{}; + auto& expected_parameters = next_accumulator->relation_parameters; for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { auto instance = instances[inst_idx]; expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; @@ -277,38 +208,21 @@ bool ProtoGalaxyVerifier_::verify_folding_proof(const std::ve instance->relation_parameters.lookup_grand_product_delta * lagranges[inst_idx]; } - auto next_eta = transcript->template receive_from_prover("next_eta"); - verified = verified & (next_eta == expected_parameters.eta); - - auto next_beta = transcript->template receive_from_prover("next_beta"); - verified = verified & (next_beta == expected_parameters.beta); - - auto next_gamma = transcript->template receive_from_prover("next_gamma"); - verified = verified & (next_gamma == expected_parameters.gamma); - - auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); - verified = verified & (next_public_input_delta == expected_parameters.public_input_delta); - - auto next_lookup_grand_product_delta = - transcript->template receive_from_prover("next_lookup_grand_product_delta"); - verified = verified & (next_lookup_grand_product_delta == expected_parameters.lookup_grand_product_delta); - - auto acc_vk = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); + next_accumulator->verification_key = + std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); auto vk_labels = commitment_labels.get_precomputed(); size_t vk_idx = 0; - for (auto& expected_vk : acc_vk->get_all()) { + for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; expected_vk = Commitment::infinity(); for (auto& instance : instances) { expected_vk = expected_vk + instance->verification_key->get_all()[vk_idx] * lagranges[inst]; inst++; } - auto vk = transcript->template receive_from_prover("next_" + vk_labels[vk_idx]); - verified = verified & (vk == expected_vk); vk_idx++; } - return verified; + return next_accumulator; } template class ProtoGalaxyVerifier_>; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp index 5743a888a0f..05dae2fb4f1 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.hpp @@ -27,8 +27,8 @@ template class ProtoGalaxyVerifier_ { CommitmentLabels commitment_labels; - ProtoGalaxyVerifier_(VerifierInstances insts) - : instances(insts){}; + ProtoGalaxyVerifier_(const std::vector>& insts) + : instances(VerifierInstances(insts)){}; ~ProtoGalaxyVerifier_() = default; /** * @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector @@ -70,7 +70,7 @@ template class ProtoGalaxyVerifier_ { * @brief Instantiatied the accumulator (i.e. the relaxed instance) from the transcript. * */ - void receive_accumulator(const std::shared_ptr&, const std::string&); + // void receive_accumulator(const std::shared_ptr&, const std::string&); /** * @brief Process the public data ϕ for the Instances to be folded. @@ -83,7 +83,7 @@ template class ProtoGalaxyVerifier_ { * accumulator, received from the prover is the same as that produced by the verifier. * */ - bool verify_folding_proof(const std::vector&); + std::shared_ptr verify_folding_proof(const std::vector&); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp index 43e8e03a370..b365edef55d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp @@ -30,6 +30,7 @@ bigfield::bigfield(Builder* parent_context, const uint256_t& value) ASSERT(value < modulus); } +// TODO(https://github.com/AztecProtocol/barretenberg/issues/850): audit the evaluate_linear_identity function template bigfield::bigfield(const field_t& low_bits_in, const field_t& high_bits_in, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.cpp new file mode 100644 index 00000000000..66a72dcd48d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.cpp @@ -0,0 +1,48 @@ +#include "barretenberg/stdlib/primitives/field/field_conversion.hpp" + +namespace bb::stdlib::field_conversion { + +/** + * @brief Converts a challenge to a fq + * @details We sometimes need challenges that are a bb::fq element, so we need to convert the bb::fr challenge to a + * bb::fq type. We do this by in a similar fashion to the convert_from_bn254_frs function that converts to a + * fq. In fact, we do call that function that the end, but we first have to split the fr into two + * pieces, one that is the 136 lower bits and one that is the 118 higher bits. Then, we can split these two pieces into + * their bigfield limbs through convert_from_bn254_frs, which is actually just a bigfield constructor that takes in two + * two-limb frs. + * + * TODO(https://github.com/AztecProtocol/barretenberg/issues/850): audit this function more carefully + * @tparam Builder + */ +template fq convert_to_grumpkin_fr(Builder& builder, const fr& f) +{ + constexpr uint64_t NUM_BITS_IN_TWO_LIMBS = 2 * NUM_LIMB_BITS; // 136 + constexpr uint64_t UPPER_TWO_LIMB_BITS = TOTAL_BITS - NUM_BITS_IN_TWO_LIMBS; // 118 + constexpr uint256_t shift = (uint256_t(1) << NUM_BITS_IN_TWO_LIMBS); + // split f into low_bits_in and high_bits_in + constexpr uint256_t LIMB_MASK = shift - 1; // mask for upper 128 bits + const uint256_t value = f.get_value(); + const uint256_t low_val = static_cast(value & LIMB_MASK); + const uint256_t hi_val = static_cast(value >> NUM_BITS_IN_TWO_LIMBS); + + fr low{ witness_t(&builder, low_val) }; + fr hi{ witness_t(&builder, hi_val) }; + // range constrain low to 136 bits and hi to 118 bits + builder.create_range_constraint(low.witness_index, NUM_BITS_IN_TWO_LIMBS, "create_range_constraint"); + builder.create_range_constraint(hi.witness_index, UPPER_TWO_LIMB_BITS, "create_range_constraint"); + + ASSERT(static_cast(low_val) + (static_cast(hi_val) << NUM_BITS_IN_TWO_LIMBS) == value); + // checks this decomposition low + hi * 2^64 = value with an assert_equal + auto sum = low + hi * shift; + builder.assert_equal(f.witness_index, sum.witness_index, "assert_equal"); + + std::vector> fr_vec{ low, hi }; + return convert_from_bn254_frs>(builder, fr_vec); +} + +template fq convert_to_grumpkin_fr(UltraCircuitBuilder& builder, + const fr& f); +template fq convert_to_grumpkin_fr( + GoblinUltraCircuitBuilder& builder, const fr& f); + +} // namespace bb::stdlib::field_conversion diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp new file mode 100644 index 00000000000..f14b05b8cd5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp @@ -0,0 +1,289 @@ +#pragma once + +#include "barretenberg/plonk/proof_system/constants.hpp" +#include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" +#include "barretenberg/stdlib/primitives/curves/bn254.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/primitives/group/cycle_group.hpp" + +namespace bb::stdlib::field_conversion { + +template using fr = field_t; +template using fq = bigfield; +template using bn254_element = element, fr, curve::BN254::Group>; +template using grumpkin_element = cycle_group; + +static constexpr uint64_t NUM_LIMB_BITS = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION; +static constexpr uint64_t TOTAL_BITS = 254; + +template fq convert_to_grumpkin_fr(Builder& builder, const fr& f); + +template inline T convert_challenge(Builder& builder, const fr& challenge) +{ + if constexpr (std::is_same_v>) { + return challenge; + } else if constexpr (std::is_same_v>) { + return convert_to_grumpkin_fr(builder, challenge); + } +} + +template inline std::array, 2> convert_grumpkin_fr_to_bn254_frs(const fq& input) +{ + fr shift(static_cast(1) << NUM_LIMB_BITS); + std::array, 2> result; + result[0] = input.binary_basis_limbs[0].element + (input.binary_basis_limbs[1].element * shift); + result[1] = input.binary_basis_limbs[2].element + (input.binary_basis_limbs[3].element * shift); + return result; +} +/** + * @brief Calculates the size of a types (in their native form) in terms of frs + * @details We want to support the following types: fr, fq, + * bn254_element, bb::Univariate, std::array, for + * FF = fr or fq, and N is arbitrary + * @tparam T + * @return constexpr size_t + */ +template constexpr size_t calc_num_bn254_frs(); + +template constexpr size_t calc_num_bn254_frs(fr* /*unused*/) +{ + return 1; +} + +template constexpr size_t calc_num_bn254_frs(fq* /*unused*/) +{ + return 2; +} + +template constexpr size_t calc_num_bn254_frs(bn254_element* /*unused*/) +{ + return 2 * calc_num_bn254_frs>(); +} + +template constexpr size_t calc_num_bn254_frs(grumpkin_element* /*unused*/) +{ + return 2 * calc_num_bn254_frs>(); +} + +template constexpr size_t calc_num_bn254_frs(std::array* /*unused*/) +{ + return N * calc_num_bn254_frs(); +} + +template constexpr size_t calc_num_bn254_frs(bb::Univariate* /*unused*/) +{ + return N * calc_num_bn254_frs(); +} + +template constexpr size_t calc_num_bn254_frs() +{ + return calc_num_bn254_frs(static_cast(nullptr)); +} + +/** + * @brief Conversions from vector of fr elements to transcript types. + * @details We want to support the following types: fr, fq, + * bn254_element, bb::Univariate, std::array, for + * FF = fr or fq, and N is arbitrary + * @tparam T + * @param fr_vec + * @return T + */ +template T convert_from_bn254_frs(Builder& builder, std::span> fr_vec); + +template +inline fr convert_from_bn254_frs(const Builder& /*unused*/, + std::span> fr_vec, + fr* /*unused*/) +{ + ASSERT(fr_vec.size() == 1); + return fr_vec[0]; +} + +template +inline fq convert_from_bn254_frs(const Builder& /*unused*/, + std::span> fr_vec, + fq* /*unused*/) +{ + ASSERT(fr_vec.size() == 2); + bigfield result(fr_vec[0], fr_vec[1], 0, 0); + return result; +} + +template +inline bn254_element convert_from_bn254_frs(Builder& builder, + std::span> fr_vec, + bn254_element* /*unused*/) +{ + ASSERT(fr_vec.size() == 4); + bn254_element val; + val.x = convert_from_bn254_frs>(builder, fr_vec.subspan(0, 2)); + val.y = convert_from_bn254_frs>(builder, fr_vec.subspan(2, 2)); + return val; +} + +template +inline grumpkin_element convert_from_bn254_frs(Builder& builder, + std::span> fr_vec, + grumpkin_element* /*unused*/) +{ + ASSERT(fr_vec.size() == 2); + grumpkin_element val(convert_from_bn254_frs>(builder, fr_vec.subspan(0, 1)), + convert_from_bn254_frs>(builder, fr_vec.subspan(1, 1)), + false); + return val; +} + +template +inline std::array, N> convert_from_bn254_frs(const Builder& /*unused*/, + std::span> fr_vec, + std::array, N>* /*unused*/) +{ + std::array, N> val; + for (size_t i = 0; i < N; ++i) { + val[i] = fr_vec[i]; + } + return val; +} + +template +inline std::array, N> convert_from_bn254_frs(Builder& builder, + std::span> fr_vec, + std::array, N>* /*unused*/) +{ + std::array, N> val; + for (size_t i = 0; i < N; ++i) { + std::vector> fr_vec_tmp{ fr_vec[2 * i], + fr_vec[2 * i + 1] }; // each pair of consecutive elements is a fq + val[i] = convert_from_bn254_frs>(builder, fr_vec_tmp); + } + return val; +} + +template +inline bb::Univariate, N> convert_from_bn254_frs(const Builder& /*unused*/, + std::span> fr_vec, + bb::Univariate, N>* /*unused*/) +{ + bb::Univariate, N> val; + for (size_t i = 0; i < N; ++i) { + val.evaluations[i] = fr_vec[i]; + } + return val; +} + +template +inline bb::Univariate, N> convert_from_bn254_frs(Builder& builder, + std::span> fr_vec, + bb::Univariate, N>* /*unused*/) +{ + bb::Univariate, N> val; + for (size_t i = 0; i < N; ++i) { + std::vector> fr_vec_tmp{ fr_vec[2 * i], fr_vec[2 * i + 1] }; + val.evaluations[i] = convert_from_bn254_frs>(builder, fr_vec_tmp); + } + return val; +} + +template +inline T convert_from_bn254_frs(Builder& builder, std::span> fr_vec) +{ + return convert_from_bn254_frs(builder, fr_vec, static_cast(nullptr)); +} + +/** + * @brief Conversion from transcript values to frs + * @details We want to support the following types: bool, size_t, uint32_t, uint64_t, fr, fq, + * bn254_element, curve::Grumpkin::AffineElement, bb::Univariate, std::array, for FF = fr/fq, and N is arbitrary. + * @tparam T + * @param val + * @return std::vector> + */ +template inline std::vector> convert_to_bn254_frs(const fq& val) +{ + auto fr_arr = convert_grumpkin_fr_to_bn254_frs(val); + std::vector> fr_vec(fr_arr.begin(), fr_arr.end()); + return fr_vec; +} + +template inline std::vector> convert_to_bn254_frs(const fr& val) +{ + std::vector> fr_vec{ val }; + return fr_vec; +} + +template inline std::vector> convert_to_bn254_frs(const bn254_element& val) +{ + auto fr_vec_x = convert_to_bn254_frs(val.x); + auto fr_vec_y = convert_to_bn254_frs(val.y); + std::vector> fr_vec(fr_vec_x.begin(), fr_vec_x.end()); + fr_vec.insert(fr_vec.end(), fr_vec_y.begin(), fr_vec_y.end()); + return fr_vec; +} + +template inline std::vector> convert_to_bn254_frs(const grumpkin_element& val) +{ + auto fr_vec_x = convert_to_bn254_frs(val.x); + auto fr_vec_y = convert_to_bn254_frs(val.y); + std::vector> fr_vec(fr_vec_x.begin(), fr_vec_x.end()); + fr_vec.insert(fr_vec.end(), fr_vec_y.begin(), fr_vec_y.end()); + return fr_vec; +} + +template +inline std::vector> convert_to_bn254_frs(const std::array, N>& val) +{ + std::vector> fr_vec(val.begin(), val.end()); + return fr_vec; +} + +template +inline std::vector> convert_to_bn254_frs(const std::array, N>& val) +{ + std::vector> fr_vec; + for (size_t i = 0; i < N; ++i) { + auto tmp_vec = convert_to_bn254_frs(val[i]); + fr_vec.insert(fr_vec.end(), tmp_vec.begin(), tmp_vec.end()); + } + return fr_vec; +} + +template +inline std::vector> convert_to_bn254_frs(const bb::Univariate, N>& val) +{ + std::vector> fr_vec; + for (size_t i = 0; i < N; ++i) { + auto tmp_vec = convert_to_bn254_frs(val.evaluations[i]); + fr_vec.insert(fr_vec.end(), tmp_vec.begin(), tmp_vec.end()); + } + return fr_vec; +} + +template +inline std::vector> convert_to_bn254_frs(const bb::Univariate, N>& val) +{ + std::vector> fr_vec; + for (size_t i = 0; i < N; ++i) { + auto tmp_vec = convert_to_bn254_frs(val.evaluations[i]); + fr_vec.insert(fr_vec.end(), tmp_vec.begin(), tmp_vec.end()); + } + return fr_vec; +} + +// TODO(https://github.com/AztecProtocol/barretenberg/issues/846): solve this annoying asymmetry - AllValues vs +// std::array, N> +template +inline std::vector> convert_to_bn254_frs(const AllValues& val) +{ + auto data = val.get_all(); + std::vector> fr_vec; + for (auto& item : data) { + auto tmp_vec = convert_to_bn254_frs(item); + fr_vec.insert(fr_vec.end(), tmp_vec.begin(), tmp_vec.end()); + } + return fr_vec; +} + +} // namespace bb::stdlib::field_conversion \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.test.cpp new file mode 100644 index 00000000000..51624b50abe --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.test.cpp @@ -0,0 +1,229 @@ +#include "barretenberg/stdlib/primitives/field/field_conversion.hpp" +#include + +namespace bb::stdlib::field_conversion_tests { + +template using fr = field_t; +template using fq = bigfield; +template using bn254_element = element, fr, curve::BN254::Group>; +template using grumpkin_element = cycle_group; + +template class StdlibFieldConversionTests : public ::testing::Test { + public: + template void check_conversion(Builder& builder, T x) + { + size_t len = bb::stdlib::field_conversion::calc_num_bn254_frs(); + auto frs = bb::stdlib::field_conversion::convert_to_bn254_frs(x); + EXPECT_EQ(len, frs.size()); + auto y = bb::stdlib::field_conversion::convert_from_bn254_frs(builder, frs); + EXPECT_EQ(x.get_value(), y.get_value()); + } + + template void check_conversion_array(Builder& builder, T x) + { + size_t len = bb::stdlib::field_conversion::calc_num_bn254_frs(); + auto frs = bb::stdlib::field_conversion::convert_to_bn254_frs(x); + EXPECT_EQ(len, frs.size()); + auto y = bb::stdlib::field_conversion::convert_from_bn254_frs(builder, frs); + EXPECT_EQ(x.size(), y.size()); + for (size_t i = 0; i < x.size(); i++) { + EXPECT_EQ(x[i].get_value(), y[i].get_value()); + } + } + + template void check_conversion_univariate(Builder& builder, T x) + { + size_t len = bb::stdlib::field_conversion::calc_num_bn254_frs(); + auto frs = bb::stdlib::field_conversion::convert_to_bn254_frs(x); + EXPECT_EQ(len, frs.size()); + auto y = bb::stdlib::field_conversion::convert_from_bn254_frs(builder, frs); + EXPECT_EQ(x.evaluations.size(), y.evaluations.size()); + for (size_t i = 0; i < x.evaluations.size(); i++) { + EXPECT_EQ(x.evaluations[i].get_value(), y.evaluations[i].get_value()); + } + } +}; + +using BuilderTypes = testing::Types; + +TYPED_TEST_SUITE(StdlibFieldConversionTests, BuilderTypes); + +/** + * @brief Field conversion test for fr + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionFr) +{ + using Builder = TypeParam; + Builder builder; + bb::fr x1_val(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits + fr x1(&builder, x1_val); + this->check_conversion(builder, x1); + + bb::fr x2_val(bb::fr::modulus_minus_two); // modulus - 2 + fr x2(&builder, x2_val); + this->check_conversion(builder, x2); + + bb::fr x3_val(1); + fr x3(&builder, x3_val); + this->check_conversion(builder, x3); +} + +/** + * @brief Field conversion test for fq + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionGrumpkinFr) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing bigfield objects with grumpkin::fr values + grumpkin::fr x1_val(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits + fq x1(&builder, x1_val); + this->check_conversion(builder, x1); +} + +/** + * @brief Field conversion test for bn254_element + * + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionBN254AffineElement) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing element objects with curve::BN254::AffineElement values + curve::BN254::AffineElement x1_val(1, 2); + bn254_element x1 = bn254_element::from_witness(&builder, x1_val); + this->check_conversion(builder, x1); + + curve::BN254::AffineElement x2_val(1, grumpkin::fr::modulus_minus_two); + bn254_element x2 = bn254_element::from_witness(&builder, x2_val); + this->check_conversion(builder, x2); +} + +/** + * @brief Field conversion test for grumpkin_element + * + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionGrumpkinAffineElement) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing element objects with curve::Grumpkin::AffineElement values + curve::Grumpkin::AffineElement x1_val(12, 100); + grumpkin_element x1 = grumpkin_element::from_witness(&builder, x1_val); + this->check_conversion(builder, x1); + + curve::Grumpkin::AffineElement x2_val(1, grumpkin::fr::modulus_minus_two); + grumpkin_element x2 = grumpkin_element::from_witness(&builder, x2_val); + this->check_conversion(builder, x2); +} + +/** + * @brief Field conversion test for std::array, N> + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionArrayBn254Fr) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing std::array objects with fr values + std::array, 4> x1{ + fr(&builder, 1), fr(&builder, 2), fr(&builder, 3), fr(&builder, 4) + }; + this->check_conversion_array(builder, x1); + + std::array, 7> x2{ fr(&builder, bb::fr::modulus_minus_two), + fr(&builder, bb::fr::modulus_minus_two - 123), + fr(&builder, 215215125), + fr(&builder, 102701750), + fr(&builder, 367032), + fr(&builder, 12985028), + fr(&builder, bb::fr::modulus_minus_two - 125015028) }; + this->check_conversion_array(builder, x2); +} + +/** + * @brief Field conversion test for std::array, N> + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionArrayGrumpkinFr) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing std::array objects with fq values + std::array, 4> x1{ + fq( + &builder, + static_cast(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789"))), + fq( + &builder, + static_cast(std::string("2bf1eaf87f7d27e8dc4056e9af975985bccc89077a21891d6c7b6ccce0631f95"))), + fq( + &builder, + static_cast(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789"))), + fq( + &builder, + static_cast(std::string("018555a8eb50cf07f64b019ebaf3af3c925c93e631f3ecd455db07bbb52bbdd3"))), + }; + this->check_conversion_array(builder, x1); +} + +/** + * @brief Field conversion test for Univariate, N> + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionUnivariateBn254Fr) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing Univariate objects with fr values + Univariate, 4> x{ + { fr(&builder, 1), fr(&builder, 2), fr(&builder, 3), fr(&builder, 4) } + }; + this->check_conversion_univariate(builder, x); +} + +/** + * @brief Field conversion test for Univariate, N> + */ +TYPED_TEST(StdlibFieldConversionTests, FieldConversionUnivariateGrumpkinFr) +{ + using Builder = TypeParam; + Builder builder; + + // Constructing std::array objects with fq values + Univariate, 4> x{ + { fq(&builder, + static_cast( + std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789"))), + fq(&builder, + static_cast( + std::string("2bf1eaf87f7d27e8dc4056e9af975985bccc89077a21891d6c7b6ccce0631f95"))), + fq(&builder, + static_cast( + std::string("018555a8eb50cf07f64b019ebaf3af3c925c93e631f3ecd455db07bbb52bbdd3"))), + fq(&builder, + static_cast( + std::string("2bf1eaf87f7d27e8dc4056e9af975985bccc89077a21891d6c7b6ccce0631f95"))) } + }; + this->check_conversion_univariate(builder, x); +} + +/** + * @brief Convert challenge test for fq + * + */ +TYPED_TEST(StdlibFieldConversionTests, ConvertChallengeGrumpkinFr) +{ + using Builder = TypeParam; + Builder builder; + + bb::fr chal_val(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); // 256 bits + auto chal = fr::from_witness(&builder, chal_val); + auto result = bb::stdlib::field_conversion::convert_challenge>(builder, chal); + auto expected = uint256_t(chal.get_value()); + EXPECT_EQ(uint256_t(result.get_value()), expected); +} +} // namespace bb::stdlib::field_conversion_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp index fc36ffcdded..9fef4b874f9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp @@ -1,104 +1,57 @@ #pragma once -#include "barretenberg/ecc/curves/bn254/fq.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/polynomials/univariate.hpp" - #include "barretenberg/transcript/transcript.hpp" -#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" -#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/utility/utility.hpp" - namespace bb::stdlib::recursion::honk { -template class Transcript { - public: - using field_ct = field_t; - using FF = bb::fr; - using NativeTranscript = BaseTranscript; - using StdlibTypes = utility::StdlibTypesUtility; - - static constexpr size_t HASH_OUTPUT_SIZE = NativeTranscript::HASH_OUTPUT_SIZE; - - NativeTranscript native_transcript; - Builder* builder; - - Transcript() = default; - Transcript(Builder* builder, const bb::HonkProof& proof_data) - : native_transcript(proof_data) - , builder(builder){}; - - /** - * @brief Get the underlying native transcript manifest (primarily for debugging) - * - */ - auto get_manifest() const { return native_transcript.get_manifest(); }; - - /** - * @brief Compute the challenges (more than 1) indicated by labels - * - * @tparam Strings - * @param labels Names of the challenges to be computed - * @return std::array Array of challenges - */ - template std::array get_challenges(const Strings&... labels) +template struct StdlibTranscriptParams { + using Fr = stdlib::field_t; + using Proof = std::vector; + static inline Fr hash(const std::vector& data) { - // Compute the indicated challenges from the native transcript - constexpr size_t num_challenges = sizeof...(Strings); - std::array native_challenges{}; - native_challenges = native_transcript.get_challenges(labels...); - - /* - * TODO(#1351): Do stdlib hashing here. E.g., for the current pedersen/blake setup, we could write data into a - * byte_array as it is received from prover, then compress via pedersen and apply blake3s. Not doing this now - * since it's a pain and we'll be revamping our hashing anyway. For now, simply convert the native hashes to - * stdlib types without adding any hashing constraints. - */ - std::array challenges; - for (size_t i = 0; i < num_challenges; ++i) { - challenges[i] = field_ct::from_witness(builder, native_challenges[i]); + if constexpr (std::is_same_v) { + ASSERT(!data.empty() && data[0].get_context() != nullptr); + Builder* builder = data[0].get_context(); + return stdlib::poseidon2::hash(*builder, data); + } else { + using NativeFr = bb::fr; + ASSERT(!data.empty() && data[0].get_context() != nullptr); + Builder* builder = data[0].get_context(); + + // call the native hash on the data + std::vector native_data; + native_data.reserve(data.size()); + for (const auto& fr : data) { + native_data.push_back(fr.get_value()); + } + NativeFr hash_value = crypto::Poseidon2::hash(native_data); + + Fr hash_field_ct = Fr::from_witness(builder, hash_value); + return hash_field_ct; } - - return challenges; } - - /** - * @brief Compute the single challenge indicated by the input label - * - * @param label Name of challenge - * @return field_ct Challenge - */ - field_ct get_challenge(const std::string& label) + template static inline T convert_challenge(const Fr& challenge) { - // Compute the indicated challenge from the native transcript - auto native_challenge = native_transcript.get_challenge(label); - - // TODO(1351): Stdlib hashing here... - - return field_ct::from_witness(builder, native_challenge); + Builder* builder = challenge.get_context(); + return bb::stdlib::field_conversion::convert_challenge(*builder, challenge); } - - /** - * @brief Extract a native element from the transcript and return a corresponding stdlib type - * - * @tparam T Type of the native element to be extracted - * @param label Name of the element - * @return The corresponding element of appropriate stdlib type - */ - template auto receive_from_prover(const std::string& label) + template static constexpr size_t calc_num_bn254_frs() { - // Get native type corresponding to input type - using NativeType = typename StdlibTypes::template NativeType::type; - - // Extract the native element from the native transcript - NativeType element = native_transcript.template receive_from_prover(label); - - // Return the corresponding stdlib type - return StdlibTypes::from_witness(builder, element); + return bb::stdlib::field_conversion::calc_num_bn254_frs(); + } + template static inline T convert_from_bn254_frs(std::span frs) + { + ASSERT(!frs.empty() && frs[0].get_context() != nullptr); + Builder* builder = frs[0].get_context(); + return bb::stdlib::field_conversion::convert_from_bn254_frs(*builder, frs); + } + template static inline std::vector convert_to_bn254_frs(const T& element) + { + Builder* builder = element.get_context(); + return bb::stdlib::field_conversion::convert_to_bn254_frs(*builder, element); } }; -} // namespace bb::stdlib::recursion::honk + +using UltraStdlibTranscript = BaseTranscript>; +using GoblinUltraStdlibTranscript = BaseTranscript>; +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp index 09c8620c619..f34292c1252 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp @@ -5,15 +5,16 @@ #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/polynomials/univariate.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb::stdlib::recursion::honk { using Builder = UltraCircuitBuilder; +using UltraFlavor = UltraFlavor; using UltraRecursiveFlavor = UltraRecursiveFlavor_; using FF = fr; -using BaseTranscript = BaseTranscript; +using NativeTranscript = NativeTranscript; +using StdlibTranscript = BaseTranscript>; /** * @brief Create some mock data; add it to the provided prover transcript in various mock rounds @@ -40,16 +41,16 @@ template auto generate_mock_proof_data(auto prover // round 0 prover_transcript.send_to_verifier("data", data); - prover_transcript.get_challenge("alpha"); + prover_transcript.template get_challenge("alpha"); // round 1 prover_transcript.send_to_verifier("scalar", scalar); prover_transcript.send_to_verifier("commitment", commitment); - prover_transcript.get_challenges("beta, gamma"); + prover_transcript.template get_challenges("beta, gamma"); // round 2 prover_transcript.send_to_verifier("univariate", univariate); - prover_transcript.get_challenges("gamma", "delta"); + prover_transcript.template get_challenges("gamma", "delta"); return prover_transcript.proof_data; } @@ -70,17 +71,17 @@ template void perform_mock_verifier_transcript_ope using Univariate = typename bb::Univariate; // round 0 - transcript.template receive_from_prover("data"); - transcript.get_challenge("alpha"); + transcript.template receive_from_prover("data"); + transcript.template get_challenge("alpha"); // round 1 transcript.template receive_from_prover("scalar"); transcript.template receive_from_prover("commitment"); - transcript.get_challenges("beta, gamma"); + transcript.template get_challenges("beta, gamma"); // round 2 transcript.template receive_from_prover("univariate"); - transcript.get_challenges("gamma", "delta"); + transcript.template get_challenges("gamma", "delta"); } /** @@ -95,18 +96,19 @@ TEST(RecursiveHonkTranscript, InterfacesMatch) constexpr size_t LENGTH = 8; // arbitrary length of Univariate to be serialized // Instantiate a Prover Transcript and use it to generate some mock proof data - BaseTranscript prover_transcript; + NativeTranscript prover_transcript; auto proof_data = generate_mock_proof_data(prover_transcript); // Instantiate a (native) Verifier Transcript with the proof data and perform some mock transcript operations - BaseTranscript native_transcript(proof_data); + NativeTranscript native_transcript(proof_data); perform_mock_verifier_transcript_operations(native_transcript); // Confirm that Prover and Verifier transcripts have generated the same manifest via the operations performed EXPECT_EQ(prover_transcript.get_manifest(), native_transcript.get_manifest()); // Instantiate a stdlib Transcript and perform the same operations - Transcript transcript{ &builder, proof_data }; + StdlibProof stdlib_proof = bb::convert_proof_to_witness(&builder, proof_data); + StdlibTranscript transcript{ stdlib_proof }; perform_mock_verifier_transcript_operations(transcript); // Confirm that the native and stdlib verifier transcripts have generated the same manifest @@ -143,27 +145,28 @@ TEST(RecursiveHonkTranscript, ReturnValuesMatch) } // Construct a mock proof via the prover transcript - BaseTranscript prover_transcript; + NativeTranscript prover_transcript; prover_transcript.send_to_verifier("scalar", scalar); prover_transcript.send_to_verifier("commitment", commitment); prover_transcript.send_to_verifier("evaluations", evaluations); - prover_transcript.get_challenges("alpha, beta"); + prover_transcript.template get_challenges("alpha, beta"); auto proof_data = prover_transcript.proof_data; // Perform the corresponding operations with the native verifier transcript - BaseTranscript native_transcript(proof_data); + NativeTranscript native_transcript(proof_data); auto native_scalar = native_transcript.template receive_from_prover("scalar"); auto native_commitment = native_transcript.template receive_from_prover("commitment"); auto native_evaluations = native_transcript.template receive_from_prover>("evaluations"); - auto [native_alpha, native_beta] = native_transcript.get_challenges("alpha", "beta"); + auto [native_alpha, native_beta] = native_transcript.template get_challenges("alpha", "beta"); // Perform the same operations with the stdlib verifier transcript - Transcript stdlib_transcript{ &builder, proof_data }; + StdlibProof stdlib_proof = bb::convert_proof_to_witness(&builder, proof_data); + StdlibTranscript stdlib_transcript{ stdlib_proof }; auto stdlib_scalar = stdlib_transcript.template receive_from_prover("scalar"); auto stdlib_commitment = stdlib_transcript.template receive_from_prover("commitment"); auto stdlib_evaluations = stdlib_transcript.template receive_from_prover>("evaluations"); - auto [stdlib_alpha, stdlib_beta] = stdlib_transcript.get_challenges("alpha", "beta"); + auto [stdlib_alpha, stdlib_beta] = stdlib_transcript.template get_challenges("alpha", "beta"); // Confirm that return values are equivalent EXPECT_EQ(native_scalar, stdlib_scalar.get_value()); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp index 5c7ef744e28..5dd711ae8f7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp @@ -1,16 +1,10 @@ #include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/sumcheck/instance/verifier_instance.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb::stdlib::recursion::honk { -template -DeciderRecursiveVerifier_::DeciderRecursiveVerifier_(Builder* builder) - : builder(builder) -{} - /** * @brief This function verifies an Ultra Honk proof for a given Flavor, produced for a relaxed instance (ϕ, \vec{β*}, * e*). @@ -24,59 +18,16 @@ std::array DeciderRecursiveVerifier_:: using ZeroMorph = ::bb::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using Transcript = typename Flavor::Transcript; - using Instance = VerifierInstance_; - - static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; - transcript = std::make_shared(builder, proof); - auto inst = std::make_unique(); - - const auto instance_size = transcript->template receive_from_prover("instance_size"); - const auto public_input_size = transcript->template receive_from_prover("public_input_size"); - const auto log_instance_size = static_cast(numeric::get_msb(uint32_t(instance_size.get_value()))); - - for (size_t i = 0; i < uint32_t(public_input_size.get_value()); ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - auto eta = transcript->template receive_from_prover("eta"); - auto beta = transcript->template receive_from_prover("beta"); - auto gamma = transcript->template receive_from_prover("gamma"); - auto public_input_delta = transcript->template receive_from_prover("public_input_delta"); - auto lookup_grand_product_delta = transcript->template receive_from_prover("lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = transcript->template receive_from_prover("alpha" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover("target_sum"); - - inst->gate_challenges = std::vector(log_instance_size); - for (size_t idx = 0; idx < log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover("gate_challenge_" + std::to_string(idx)); - } - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = transcript->template receive_from_prover(witness_labels[idx]); - } - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(vk_labels[idx]); - } + StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); + transcript = std::make_shared(stdlib_proof); - VerifierCommitments commitments{ inst->verification_key, inst->witness_commitments }; + VerifierCommitments commitments{ accumulator->verification_key, accumulator->witness_commitments }; - auto sumcheck = Sumcheck(log_instance_size, transcript, inst->target_sum); + auto sumcheck = Sumcheck(accumulator->log_instance_size, transcript, accumulator->target_sum); auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(inst->relation_parameters, inst->alphas, inst->gate_challenges); + sumcheck.verify(accumulator->relation_parameters, accumulator->alphas, accumulator->gate_challenges); // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the // unrolled protocol. @@ -90,6 +41,6 @@ std::array DeciderRecursiveVerifier_:: return pairing_points; } -template class DeciderRecursiveVerifier_>; +// template class DeciderRecursiveVerifier_>; template class DeciderRecursiveVerifier_>; } // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp index 56f8ec1c46d..829f47e99a5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp @@ -3,10 +3,11 @@ #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" - namespace bb::stdlib::recursion::honk { template class DeciderRecursiveVerifier_ { + using NativeFlavor = typename Flavor::NativeFlavor; using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using GroupElement = typename Flavor::GroupElement; @@ -15,16 +16,22 @@ template class DeciderRecursiveVerifier_ { using Builder = typename Flavor::CircuitBuilder; using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; + using Instance = RecursiveVerifierInstance_; + using NativeInstance = bb::VerifierInstance_; + using Transcript = bb::BaseTranscript>; public: - explicit DeciderRecursiveVerifier_(Builder* builder); + explicit DeciderRecursiveVerifier_(Builder* builder, std::shared_ptr accumulator) + : builder(builder) + , accumulator(std::make_shared(builder, accumulator)){}; PairingPoints verify_proof(const HonkProof& proof); std::map commitments; std::shared_ptr pcs_verification_key; Builder* builder; - std::shared_ptr> transcript; + std::shared_ptr accumulator; + std::shared_ptr transcript; }; } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index 9052d25c071..f74d18faccb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -148,21 +148,22 @@ template class GoblinRecursiveVerifierTest : public testi // Compute native verification key InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK // Instantiate the recursive verifier using the native verification key - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; // Spot check some values in the recursive VK to ensure it was constructed correctly - EXPECT_EQ(verifier.key->circuit_size, instance->verification_key->circuit_size); - EXPECT_EQ(verifier.key->log_circuit_size, instance->verification_key->log_circuit_size); - EXPECT_EQ(verifier.key->num_public_inputs, instance->verification_key->num_public_inputs); - EXPECT_EQ(verifier.key->q_m.get_value(), instance->verification_key->q_m); - EXPECT_EQ(verifier.key->q_r.get_value(), instance->verification_key->q_r); - EXPECT_EQ(verifier.key->sigma_1.get_value(), instance->verification_key->sigma_1); - EXPECT_EQ(verifier.key->id_3.get_value(), instance->verification_key->id_3); - EXPECT_EQ(verifier.key->lagrange_ecc_op.get_value(), instance->verification_key->lagrange_ecc_op); + EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); + EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); + EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); + EXPECT_EQ(verifier.key->q_m.get_value(), verification_key->q_m); + EXPECT_EQ(verifier.key->q_r.get_value(), verification_key->q_r); + EXPECT_EQ(verifier.key->sigma_1.get_value(), verification_key->sigma_1); + EXPECT_EQ(verifier.key->id_3.get_value(), verification_key->id_3); + EXPECT_EQ(verifier.key->lagrange_ecc_op.get_value(), verification_key->lagrange_ecc_op); } /** @@ -176,13 +177,14 @@ template class GoblinRecursiveVerifierTest : public testi // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Goblin: num gates = ", outer_circuit.num_gates); @@ -191,7 +193,7 @@ template class GoblinRecursiveVerifierTest : public testi // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance); + auto native_verifier = inner_composer.create_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -208,9 +210,10 @@ template class GoblinRecursiveVerifierTest : public testi // Check 3: Construct and verify a proof of the recursive verifier circuit { auto composer = get_outer_composer(); - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -231,7 +234,8 @@ template class GoblinRecursiveVerifierTest : public testi // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -243,7 +247,7 @@ template class GoblinRecursiveVerifierTest : public testi // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp index 28fbe6d92df..49bb9aa1c23 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp @@ -18,7 +18,9 @@ template std::array::Element, 2> MergeRecursiveVerifier_::verify_proof( const HonkProof& proof) { - transcript = std::make_shared(builder, proof); + // transform it into stdlib proof + StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); + transcript = std::make_shared(stdlib_proof); // Receive commitments [t_i^{shift}], [T_{i-1}], and [T_i] std::array C_T_prev; @@ -30,7 +32,7 @@ std::array::Element, 2> MergeRecursiveVerifier_template receive_from_prover("T_CURRENT_" + std::to_string(idx + 1)); } - FF kappa = transcript->get_challenge("kappa"); + FF kappa = transcript->template get_challenge("kappa"); // Receive transcript poly evaluations and add corresponding univariate opening claims {(\kappa, p(\kappa), [p(X)]} std::array T_prev_evals; @@ -56,7 +58,7 @@ std::array::Element, 2> MergeRecursiveVerifier_get_challenge("alpha"); + FF alpha = transcript->template get_challenge("alpha"); // Constuct batched commitment and batched evaluation from constituents using batching challenge \alpha std::vector scalars; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp index 9e5a76fbc8d..f8780359937 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp @@ -14,7 +14,7 @@ template class MergeRecursiveVerifier_ { using KZG = ::bb::KZG; using OpeningClaim = ::bb::OpeningClaim; using PairingPoints = std::array; - using Transcript = honk::Transcript; + using Transcript = bb::BaseTranscript>; CircuitBuilder* builder; std::shared_ptr transcript; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index af5b40ecfc3..4b02a451818 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -29,6 +29,8 @@ class RecursiveMergeVerifierTest : public testing::Test { using Commitment = InnerFlavor::Commitment; using FF = InnerFlavor::FF; using VerifierCommitmentKey = bb::VerifierCommitmentKey; + using MergeProver = MergeProver_; + using MergeVerifier = MergeVerifier_; public: static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } @@ -80,9 +82,10 @@ class RecursiveMergeVerifierTest : public testing::Test { // Check 3: Construct and verify a (goblin) ultra honk proof of the Merge recursive verifier circuit { GoblinUltraComposer composer; - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp index e0fed9ac6a2..9652935a9f1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp @@ -1,77 +1,17 @@ #include "protogalaxy_recursive_verifier.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" namespace bb::stdlib::recursion::honk { -template -void ProtoGalaxyRecursiveVerifier_::receive_accumulator(const std::shared_ptr& inst, - const std::string& domain_separator) -{ - // Get circuit parameters - const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); - const auto public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - inst->instance_size = uint32_t(instance_size.get_value()); - inst->log_instance_size = uint32_t(numeric::get_msb(inst->instance_size)); - inst->public_input_size = uint32_t(public_input_size.get_value()); - - // Get folded public inputs - for (size_t i = 0; i < inst->public_input_size; ++i) { - auto public_input_i = - transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->public_inputs.emplace_back(public_input_i); - } - - // Get folded relation parameters - auto eta = transcript->template receive_from_prover(domain_separator + "_eta"); - auto beta = transcript->template receive_from_prover(domain_separator + "_beta"); - auto gamma = transcript->template receive_from_prover(domain_separator + "_gamma"); - auto public_input_delta = transcript->template receive_from_prover(domain_separator + "_public_input_delta"); - auto lookup_grand_product_delta = - transcript->template receive_from_prover(domain_separator + "_lookup_grand_product_delta"); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; - - // Get the folded relation separator challenges \vec{α} - for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = - transcript->template receive_from_prover(domain_separator + "_alpha_" + std::to_string(idx)); - } - - inst->target_sum = transcript->template receive_from_prover(domain_separator + "_target_sum"); - - // Get the folded gate challenges, \vec{β} in the paper - inst->gate_challenges = std::vector(inst->log_instance_size); - for (size_t idx = 0; idx < inst->log_instance_size; idx++) { - inst->gate_challenges[idx] = - transcript->template receive_from_prover(domain_separator + "_gate_challenge_" + std::to_string(idx)); - } - - // Get the folded commitments to all witness polynomials - auto comm_view = inst->witness_commitments.get_all(); - auto witness_labels = inst->commitment_labels.get_witness(); - for (size_t idx = 0; idx < witness_labels.size(); idx++) { - comm_view[idx] = - transcript->template receive_from_prover(domain_separator + "_" + witness_labels[idx]); - } - - // Get the folded commitments to selector polynomials - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = inst->commitment_labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); - } -} - template void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_instance( const std::shared_ptr& inst, const std::string& domain_separator) { // Get circuit parameters and the public inputs - const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); + const auto instance_size = transcript->template receive_from_prover(domain_separator + "_instance_size"); const auto public_input_size = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); + transcript->template receive_from_prover(domain_separator + "_public_input_size"); inst->instance_size = uint32_t(instance_size.get_value()); inst->log_instance_size = static_cast(numeric::get_msb(inst->instance_size)); inst->public_input_size = uint32_t(public_input_size.get_value()); @@ -83,7 +23,7 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst } const auto pub_inputs_offset = - transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); + transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); inst->pub_inputs_offset = uint32_t(pub_inputs_offset.get_value()); @@ -110,13 +50,14 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst } // Get challenge for sorted list batching and wire four memory records commitment - auto eta = transcript->get_challenge(domain_separator + "_eta"); + auto eta = transcript->template get_challenge(domain_separator + "_eta"); witness_commitments.sorted_accum = transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); // Get permutation challenges and commitment to permutation and lookup grand products - auto [beta, gamma] = transcript->get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); + auto [beta, gamma] = + transcript->template get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial if constexpr (IsGoblinFlavor) { @@ -138,15 +79,7 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { - inst->alphas[idx] = transcript->get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); - } - - // Get the commitments to the selector polynomials for the given instance - inst->verification_key = std::make_shared(inst->instance_size, inst->public_input_size); - auto vk_view = inst->verification_key->get_all(); - auto vk_labels = labels.get_precomputed(); - for (size_t idx = 0; idx < vk_labels.size(); idx++) { - vk_view[idx] = transcript->template receive_from_prover(domain_separator + "_" + vk_labels[idx]); + inst->alphas[idx] = transcript->template get_challenge(domain_separator + "_alpha_" + std::to_string(idx)); } } @@ -157,17 +90,10 @@ template void ProtoGalaxyRecursiveVerifier_template receive_from_prover(domain_separator + "is_accumulator"); - inst->is_accumulator = static_cast(is_accumulator.get_value()); - if (inst->is_accumulator) { - receive_accumulator(inst, domain_separator); - } else { - // This is the first round of folding and we need to generate some gate challenges. - // TODO(https://github.com/AztecProtocol/barretenberg/issues/740): implement option 2 to make this more - // efficient by avoiding the computation of the perturbator + if (!inst->is_accumulator) { receive_and_finalise_instance(inst, domain_separator); inst->target_sum = 0; - auto beta = transcript->get_challenge(domain_separator + "_initial_gate_challenge"); + auto beta = transcript->template get_challenge(domain_separator + "_initial_gate_challenge"); std::vector gate_challenges(inst->log_instance_size); gate_challenges[0] = beta; for (size_t i = 1; i < inst->log_instance_size; i++) { @@ -185,32 +111,27 @@ template void ProtoGalaxyRecursiveVerifier_ -void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(const HonkProof& proof) +std::shared_ptr ProtoGalaxyRecursiveVerifier_< + VerifierInstances>::verify_folding_proof(const HonkProof& proof) { using Transcript = typename Flavor::Transcript; - using ElementNative = typename Flavor::Curve::ElementNative; - using AffineElementNative = typename Flavor::Curve::AffineElementNative; - using ScalarNative = typename Flavor::Curve::ScalarFieldNative; - transcript = std::make_shared(builder, proof); + StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); + transcript = std::make_shared(stdlib_proof); prepare_for_folding(); - auto delta = transcript->get_challenge("delta"); + auto delta = transcript->template get_challenge("delta"); auto accumulator = get_accumulator(); auto deltas = compute_round_challenge_pows(accumulator->log_instance_size, delta); std::vector perturbator_coeffs(accumulator->log_instance_size + 1); - for (size_t idx = 0; idx <= accumulator->log_instance_size; idx++) { + for (size_t idx = 1; idx <= accumulator->log_instance_size; idx++) { perturbator_coeffs[idx] = transcript->template receive_from_prover("perturbator_" + std::to_string(idx)); } - // TODO(https://github.com/AztecProtocol/barretenberg/issues/833): As currently the stdlib transcript is not - // creating proper constraints linked to Fiat-Shamir we add an additonal gate to ensure assert_equal is correct. - // This comparison to 0 can be removed here and below once we have merged the transcript. - auto zero = FF::from_witness(builder, ScalarNative(0)); - zero.assert_equal(accumulator->target_sum - perturbator_coeffs[0], "F(0) != e"); + perturbator_coeffs[0] = accumulator->target_sum; - FF perturbator_challenge = transcript->get_challenge("perturbator_challenge"); + FF perturbator_challenge = transcript->template get_challenge("perturbator_challenge"); auto perturbator_at_challenge = evaluate_perturbator(perturbator_coeffs, perturbator_challenge); // The degree of K(X) is dk - k - 1 = k(d - 1) - 1. Hence we need k(d - 1) evaluations to represent it. @@ -221,72 +142,66 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons } Univariate combiner_quotient( combiner_quotient_evals); - FF combiner_challenge = transcript->get_challenge("combiner_quotient_challenge"); + FF combiner_challenge = transcript->template get_challenge("combiner_quotient_challenge"); auto combiner_quotient_at_challenge = combiner_quotient.evaluate(combiner_challenge); // fine recursive i think auto vanishing_polynomial_at_challenge = combiner_challenge * (combiner_challenge - FF(1)); auto lagranges = std::vector{ FF(1) - combiner_challenge, combiner_challenge }; + auto next_accumulator = std::make_shared(builder); + next_accumulator->instance_size = accumulator->instance_size; + next_accumulator->log_instance_size = accumulator->log_instance_size; + next_accumulator->is_accumulator = true; + // Compute next folding parameters and verify against the ones received from the prover - auto expected_next_target_sum = + next_accumulator->target_sum = perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; - auto next_target_sum = transcript->template receive_from_prover("next_target_sum"); - zero.assert_equal(expected_next_target_sum - next_target_sum, "next target sum mismatch"); - - auto expected_betas_star = update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); - for (size_t idx = 0; idx < accumulator->log_instance_size; idx++) { - auto beta_star = transcript->template receive_from_prover("next_gate_challenge_" + std::to_string(idx)); - zero.assert_equal(beta_star - expected_betas_star[idx], - " next gate challenge mismatch at: " + std::to_string(idx)); - } + next_accumulator->gate_challenges = + update_gate_challenges(perturbator_challenge, accumulator->gate_challenges, deltas); // Compute ϕ and verify against the data received from the prover - WitnessCommitments acc_witness_commitments; + auto& acc_witness_commitments = next_accumulator->witness_commitments; auto witness_labels = commitment_labels.get_witness(); size_t comm_idx = 0; - auto random_generator = Commitment::from_witness(builder, AffineElementNative(ElementNative::random_element())); - for (auto& expected_comm : acc_witness_commitments.get_all()) { - expected_comm = random_generator; + for (auto& comm : acc_witness_commitments.get_all()) { + std::vector scalars; + std::vector commitments; size_t inst = 0; for (auto& instance : instances) { - expected_comm = expected_comm + instance->witness_commitments.get_all()[comm_idx] * lagranges[inst]; + scalars.emplace_back(lagranges[inst]); + commitments.emplace_back(instance->witness_commitments.get_all()[comm_idx]); inst++; } - auto comm = transcript->template receive_from_prover("next_" + witness_labels[comm_idx]); - auto res = expected_comm - comm; - random_generator.x.assert_equal(res.x); - random_generator.y.assert_equal(res.y); + comm = Commitment::batch_mul(commitments, scalars); comm_idx++; } - std::vector folded_public_inputs(instances[0]->public_inputs.size(), 0); + next_accumulator->public_input_size = instances[0]->public_input_size; + next_accumulator->public_inputs = std::vector(next_accumulator->public_input_size, 0); size_t public_input_idx = 0; - for (auto& expected_public_input : folded_public_inputs) { + for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; for (auto& instance : instances) { - expected_public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; - inst++; + if (instance->public_inputs.size() >= next_accumulator->public_inputs.size()) { + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; + inst++; + }; } - auto next_public_input = - transcript->template receive_from_prover("next_public_input" + std::to_string(public_input_idx)); - zero.assert_equal(expected_public_input - next_public_input, - "folded public input mismatch at: " + std::to_string(public_input_idx)); public_input_idx++; } - for (size_t alpha_idx = 0; alpha_idx < NUM_SUBRELATIONS - 1; alpha_idx++) { - FF expected_alpha(0); + size_t alpha_idx = 0; + for (auto& alpha : next_accumulator->alphas) { + alpha = FF(0); size_t instance_idx = 0; for (auto& instance : instances) { - expected_alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; + alpha += instance->alphas[alpha_idx] * lagranges[instance_idx]; instance_idx++; } - auto next_alpha = transcript->template receive_from_prover("next_alpha_" + std::to_string(alpha_idx)); - zero.assert_equal(expected_alpha - next_alpha, - "folded relation separator mismatch at: " + std::to_string(alpha_idx)); + alpha_idx++; } - auto expected_parameters = bb::RelationParameters{}; + auto& expected_parameters = next_accumulator->relation_parameters; for (size_t inst_idx = 0; inst_idx < VerifierInstances::NUM; inst_idx++) { auto instance = instances[inst_idx]; expected_parameters.eta += instance->relation_parameters.eta * lagranges[inst_idx]; @@ -298,43 +213,27 @@ void ProtoGalaxyRecursiveVerifier_::verify_folding_proof(cons instance->relation_parameters.lookup_grand_product_delta * lagranges[inst_idx]; } - auto next_eta = transcript->template receive_from_prover("next_eta"); - zero.assert_equal(expected_parameters.eta - next_eta, "relation parameter eta mismatch"); - - auto next_beta = transcript->template receive_from_prover("next_beta"); - zero.assert_equal(expected_parameters.beta - next_beta, "relation parameter beta mismatch"); - - auto next_gamma = transcript->template receive_from_prover("next_gamma"); - zero.assert_equal(expected_parameters.gamma - next_gamma, "relation parameter gamma mismatch"); - - auto next_public_input_delta = transcript->template receive_from_prover("next_public_input_delta"); - zero.assert_equal(expected_parameters.public_input_delta - next_public_input_delta, - "relation parameter public input delta mismatch"); - - auto next_lookup_grand_product_delta = - transcript->template receive_from_prover("next_lookup_grand_product_delta"); - zero.assert_equal(expected_parameters.lookup_grand_product_delta - next_lookup_grand_product_delta, - "relation parameter lookup grand product delta mismatch"); - - auto acc_vk = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); + next_accumulator->verification_key = + std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); auto vk_labels = commitment_labels.get_precomputed(); size_t vk_idx = 0; - for (auto& expected_vk : acc_vk->get_all()) { + for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; - expected_vk = random_generator; + std::vector scalars; + std::vector commitments; for (auto& instance : instances) { - expected_vk = expected_vk + instance->verification_key->get_all()[vk_idx] * lagranges[inst]; + scalars.emplace_back(lagranges[inst]); + commitments.emplace_back(instance->verification_key->get_all()[vk_idx]); inst++; } - auto vk = transcript->template receive_from_prover("next_" + vk_labels[vk_idx]); - auto res = expected_vk - vk; - random_generator.x.assert_equal(res.x); - random_generator.y.assert_equal(res.y); + expected_vk = Commitment::batch_mul(commitments, scalars); vk_idx++; } + return next_accumulator; } -template class ProtoGalaxyRecursiveVerifier_, 2>>; +// template class ProtoGalaxyRecursiveVerifier_, +// 2>>; template class ProtoGalaxyRecursiveVerifier_< - VerifierInstances_, 2>>; + RecursiveVerifierInstances_, 2>>; } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp index 15fc8dabae3..f413fb3b151 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp @@ -5,35 +5,42 @@ #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/protogalaxy/folding_result.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" -#include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" namespace bb::stdlib::recursion::honk { template class ProtoGalaxyRecursiveVerifier_ { public: using Flavor = typename VerifierInstances::Flavor; + using NativeFlavor = typename Flavor::NativeFlavor; using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; using GroupElement = typename Flavor::GroupElement; using Instance = typename VerifierInstances::Instance; + using NativeInstance = bb::VerifierInstance_; using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using Builder = typename Flavor::CircuitBuilder; using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; + static constexpr size_t NUM = VerifierInstances::NUM; + using Transcript = bb::BaseTranscript>; static constexpr size_t NUM_SUBRELATIONS = Flavor::NUM_SUBRELATIONS; - VerifierInstances instances; - CommitmentLabels commitment_labels; Builder* builder; - std::shared_ptr> transcript; + std::shared_ptr transcript; + VerifierInstances instances; + + ProtoGalaxyRecursiveVerifier_(Builder* builder, + std::shared_ptr accumulator, + const std::vector> native_inst_vks) + : builder(builder) + , instances(VerifierInstances(builder, accumulator, native_inst_vks)){}; - explicit ProtoGalaxyRecursiveVerifier_(Builder* builder) - : instances(VerifierInstances()) - , builder(builder){}; /** * @brief Given a new round challenge δ for each iteration of the full ProtoGalaxy protocol, compute the vector * [δ, δ^2,..., δ^t] where t = logn and n is the size of the instance. @@ -91,7 +98,7 @@ template class ProtoGalaxyRecursiveVerifier_ { * by the prover, are expressed as constraints. */ - void verify_folding_proof(const HonkProof& proof); + std::shared_ptr verify_folding_proof(const HonkProof&); /** * @brief Evaluates the perturbator at a given scalar, in a sequential manner for the recursive setting. diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 0912edf91ce..19566c92d00 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -16,7 +16,9 @@ template class ProtoGalaxyRecursiveTests : public tes using InnerFlavor = typename RecursiveFlavor::NativeFlavor; using InnerComposer = ::bb::UltraComposer_; - using Instance = ::bb::ProverInstance_; + using ProverInstance = ::bb::ProverInstance_; + using VerifierInstance = ::bb::VerifierInstance_; + using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; using InnerBuilder = typename InnerComposer::CircuitBuilder; using InnerCurve = bn254; using Commitment = typename InnerFlavor::Commitment; @@ -26,7 +28,7 @@ template class ProtoGalaxyRecursiveTests : public tes using OuterBuilder = GoblinUltraCircuitBuilder; using OuterComposer = GoblinUltraComposer; - using RecursiveVerifierInstances = ::bb::VerifierInstances_; + using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; using DeciderRecursiveVerifier = DeciderRecursiveVerifier_; using DeciderVerifier = DeciderVerifier_; @@ -55,7 +57,7 @@ template class ProtoGalaxyRecursiveTests : public tes * TODO(https://github.com/AztecProtocol/barretenberg/issues/744): make testing utility with functionality shared * amongst test files */ - static void create_inner_circuit(InnerBuilder& builder, size_t log_num_gates = 10) + static void create_inner_circuit(InnerBuilder& builder, size_t log_num_gates = 15) { using fr_ct = typename InnerCurve::ScalarField; using fq_ct = typename InnerCurve::BaseField; @@ -111,17 +113,17 @@ template class ProtoGalaxyRecursiveTests : public tes } }; - static std::shared_ptr fold_and_verify_native(const std::vector>& instances, - InnerComposer& composer) + static std::tuple, std::shared_ptr> fold_and_verify_native( + const std::vector>& prover_instances, + const std::vector>& verifier_instances, + InnerComposer& composer) { - auto folding_prover = composer.create_folding_prover(instances); - auto folding_verifier = composer.create_folding_verifier(); - - auto proof = folding_prover.fold_instances(); - auto next_accumulator = proof.accumulator; - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, true); - return next_accumulator; + auto folding_prover = composer.create_folding_prover(prover_instances); + auto folding_verifier = composer.create_folding_verifier(verifier_instances); + + auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); + auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); + return { prover_accumulator, verifier_accumulator }; } /** @@ -165,39 +167,39 @@ template class ProtoGalaxyRecursiveTests : public tes }; /** - * @brief Tests a simple recursive fold that is valid works as expected. + * @brief Tests that a valid recursive fold works as expected. * */ static void test_recursive_folding() { // Create two arbitrary circuits for the first round of folding InnerBuilder builder1; - create_inner_circuit(builder1); InnerBuilder builder2; - builder2.add_public_variable(FF(1)); create_inner_circuit(builder2); InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - + auto prover_instance_1 = inner_composer.create_prover_instance(builder1); + auto verifier_instance_1 = inner_composer.create_verifier_instance(prover_instance_1); + auto prover_instance_2 = inner_composer.create_prover_instance(builder2); + auto verifier_instance_2 = inner_composer.create_verifier_instance(prover_instance_2); // Generate a folding proof - auto inner_folding_prover = inner_composer.create_folding_prover(instances); + auto inner_folding_prover = inner_composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); auto inner_folding_proof = inner_folding_prover.fold_instances(); // Create a recursive folding verifier circuit for the folding proof of the two instances OuterBuilder outer_folding_circuit; - FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; - verifier.verify_folding_proof(inner_folding_proof.folding_data); + auto verifier = FoldingRecursiveVerifier( + &outer_folding_circuit, verifier_instance_1, { verifier_instance_2->verification_key }); + auto recursive_verifier_accumulator = verifier.verify_folding_proof(inner_folding_proof.folding_data); + auto acc = std::make_shared(recursive_verifier_accumulator->get_value()); info("Folding Recursive Verifier: num gates = ", outer_folding_circuit.num_gates); - // Perform native folding verification and ensure it returns the same result (either true or false) as calling - // check_circuit on the recursive folding verifier - auto native_folding_verifier = inner_composer.create_folding_verifier(); - auto native_folding_result = native_folding_verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(native_folding_result, !outer_folding_circuit.failed()); + // Perform native folding verification and ensure it returns the same result (either true or false) as + // calling check_circuit on the recursive folding verifier + auto native_folding_verifier = + inner_composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + auto verifier_accumulator = native_folding_verifier.verify_folding_proof(inner_folding_proof.folding_data); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the // manifestsproduced by each agree. @@ -208,87 +210,31 @@ template class ProtoGalaxyRecursiveTests : public tes EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); } - // Check for a failure flag in the recursive verifier circuit - EXPECT_EQ(outer_folding_circuit.failed(), false) << outer_folding_circuit.err(); - - { - auto composer = OuterComposer(); - auto instance = composer.create_instance(outer_folding_circuit); - auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); - auto proof = prover.construct_proof(); - bool verified = verifier.verify_proof(proof); - - ASSERT(verified); - } - }; - - /** - * @brief Perform two rounds of folding valid circuits and then recursive verify the final decider proof, - * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native - * verifiers are identical by checking the manifests - */ - // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in tests once - // we can fold instances of different sizes. - static void test_full_protogalaxy_recursive() - { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify_native(instances, inner_composer); - - // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - instances = std::vector>{ accumulator, instance3 }; - - accumulator = fold_and_verify_native(instances, inner_composer); - - // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + auto inner_decider_prover = inner_composer.create_decider_prover(inner_folding_proof.accumulator); auto inner_decider_proof = inner_decider_prover.construct_proof(); - // Create a decider verifier circuit for recursively verifying the decider proof OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit, acc }; auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); - // Perform native verification then perform the pairing on the outputs of the recursive - // decider verifier and check that the result agrees. - DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(accumulator); + // Check for a failure flag in the recursive verifier circuit + EXPECT_EQ(outer_folding_circuit.failed(), false) << outer_folding_circuit.err(); + + DeciderVerifier native_decider_verifier = inner_composer.create_decider_verifier(verifier_accumulator); auto native_result = native_decider_verifier.verify_proof(inner_decider_proof); auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check( pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(native_result, recursive_result); - // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring - // the manifests produced are the same. - auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); - auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); - for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { - EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); - } - - // Construct and verify a proof of the recursive decider verifier circuit { auto composer = OuterComposer(); - auto instance = composer.create_instance(outer_decider_circuit); + auto instance = composer.create_prover_instance(outer_folding_circuit); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -296,80 +242,153 @@ template class ProtoGalaxyRecursiveTests : public tes } }; - static void test_tampered_decider_proof() - { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify_native(instances, inner_composer); - - // Tamper with the accumulator by changing the target sum - accumulator->target_sum = FF::random_element(); - - // Create a decider proof for the relaxed instance obtained through folding - auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); - auto inner_decider_proof = inner_decider_prover.construct_proof(); - - // Create a decider verifier circuit for recursively verifying the decider proof - OuterBuilder outer_decider_circuit; - DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; - decider_verifier.verify_proof(inner_decider_proof); - info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); - - // We expect the decider circuit check to fail due to the bad proof - EXPECT_FALSE(outer_decider_circuit.check_circuit()); - }; - - static void test_tampered_accumulator() - { - // Create two arbitrary circuits for the first round of folding - InnerBuilder builder1; - - create_inner_circuit(builder1); - InnerBuilder builder2; - builder2.add_public_variable(FF(1)); - create_inner_circuit(builder2); - - InnerComposer inner_composer = InnerComposer(); - auto instance1 = inner_composer.create_instance(builder1); - auto instance2 = inner_composer.create_instance(builder2); - auto instances = std::vector>{ instance1, instance2 }; - - auto accumulator = fold_and_verify_native(instances, inner_composer); - - // Create another circuit to do a second round of folding - InnerBuilder builder3; - create_inner_circuit(builder3); - auto instance3 = inner_composer.create_instance(builder3); - - // Tamper with the accumulator - instances = std::vector>{ accumulator, instance3 }; - accumulator->prover_polynomials.w_l[1] = FF::random_element(); - - // Generate a folding proof - auto inner_folding_prover = inner_composer.create_folding_prover(instances); - auto inner_folding_proof = inner_folding_prover.fold_instances(); - - // Create a recursive folding verifier circuit for the folding proof of the two instances - OuterBuilder outer_folding_circuit; - FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; - verifier.verify_folding_proof(inner_folding_proof.folding_data); - EXPECT_EQ(outer_folding_circuit.check_circuit(), false); - }; + /** + * @brief Perform two rounds of folding valid circuits and then recursive verify the final decider proof, + * make sure the verifer circuits pass check_circuit(). Ensure that the algorithm of the recursive and native + * verifiers are identical by checking the manifests + */ + // TODO(https://github.com/AztecProtocol/barretenberg/issues/844): Fold the recursive folding verifier in + // tests once + // we can fold instances of different sizes. + // static void test_full_protogalaxy_recursive() + // { + // // Create two arbitrary circuits for the first round of folding + // InnerBuilder builder1; + + // create_inner_circuit(builder1); + // InnerBuilder builder2; + // builder2.add_public_variable(FF(1)); + // create_inner_circuit(builder2); + + // InnerComposer inner_composer = InnerComposer(); + // auto prover_instance_1 = inner_composer.create_prover_instance(builder1); + // auto verifier_instance_1 = inner_composer.create_verifier_instance(prover_instance_1); + // auto prover_instance_2 = inner_composer.create_prover_instance(builder2); + // auto verifier_instance_2 = inner_composer.create_verifier_instance(prover_instance_2); + + // auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native( + // { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, + // tinner_composer); + + // // Create another circuit to do a second round of folding + // InnerBuilder builder3; + // create_inner_circuit(builder3); + // auto prover_instance_3 = inner_composer.create_prover_instance(builder3); + // auto verifier_instance_3 = inner_composer.create_verifier_instance(prover_instance_3); + + // auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify_native( + // { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, + // inner_composer); + + // // Create a decider proof for the relaxed instance obtained through folding + // auto inner_decider_prover = inner_composer.create_decider_prover(prover_accumulator_2); + // auto inner_decider_proof = inner_decider_prover.construct_proof(); + + // // Create a decider verifier circuit for recursively verifying the decider proof + // OuterBuilder outer_decider_circuit; + // DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + // auto pairing_points = decider_verifier.verify_proof(inner_decider_proof); + // info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + // // Check for a failure flag in the recursive verifier circuit + // EXPECT_EQ(outer_decider_circuit.failed(), false) << outer_decider_circuit.err(); + + // // Perform native verification then perform the pairing on the outputs of the recursive + // // decider verifier and check that the result agrees. + + // // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring + // // the manifests produced are the same. + // auto recursive_decider_manifest = decider_verifier.transcript->get_manifest(); + // auto native_decider_manifest = native_decider_verifier.transcript->get_manifest(); + // for (size_t i = 0; i < recursive_decider_manifest.size(); ++i) { + // EXPECT_EQ(recursive_decider_manifest[i], native_decider_manifest[i]); + // } + + // // Construct and verify a proof of the recursive decider verifier circuit + // { + // auto composer = OuterComposer(); + // auto instance = composer.create_prover_instance(outer_decider_circuit); + // auto prover = composer.create_prover(instance); + // auto verifier = composer.create_verifier(instance); + // auto proof = prover.construct_proof(); + // bool verified = verifier.verify_proof(proof); + + // ASSERT(verified); + // } + // }; + + // static void test_tampered_decider_proof() + // { + // // Create two arbitrary circuits for the first round of folding + // InnerBuilder builder1; + + // create_inner_circuit(builder1); + // InnerBuilder builder2; + // builder2.add_public_variable(FF(1)); + // create_inner_circuit(builder2); + + // InnerComposer inner_composer = InnerComposer(); + // auto prover_instance_1 = inner_composer.create_prover_instance(builder1); + // auto prover_instance_2 = inner_composer.create_prover_instance(builder2); + // auto instances = std::vector>{ prover_instance_1, prover_instance_2 }; + + // auto accumulator = fold_and_verify_native(instances, inner_composer); + + // // Tamper with the accumulator by changing the target sum + // accumulator->target_sum = FF::random_element(); + + // // Create a decider proof for the relaxed instance obtained through folding + // auto inner_decider_prover = inner_composer.create_decider_prover(accumulator); + // auto inner_decider_proof = inner_decider_prover.construct_proof(); + + // // Create a decider verifier circuit for recursively verifying the decider proof + // OuterBuilder outer_decider_circuit; + // DeciderRecursiveVerifier decider_verifier{ &outer_decider_circuit }; + // decider_verifier.verify_proof(inner_decider_proof); + // info("Decider Recursive Verifier: num gates = ", outer_decider_circuit.num_gates); + + // // We expect the decider circuit check to fail due to the bad proof + // EXPECT_FALSE(outer_decider_circuit.check_circuit()); + // }; + + // static void test_tampered_accumulator() + // { + // // Create two arbitrary circuits for the first round of folding + // InnerBuilder builder1; + + // create_inner_circuit(builder1); + // InnerBuilder builder2; + // builder2.add_public_variable(FF(1)); + // create_inner_circuit(builder2); + + // InnerComposer inner_composer = InnerComposer(); + // auto prover_instance_1 = inner_composer.create_prover_instance(builder1); + // auto prover_instance_2 = inner_composer.create_prover_instance(builder2); + // auto instances = std::vector>{ prover_instance_1, prover_instance_2 }; + + // auto accumulator = fold_and_verify_native(instances, inner_composer); + + // // Create another circuit to do a second round of folding + // InnerBuilder builder3; + // create_inner_circuit(builder3); + // auto instance3 = inner_composer.create_prover_instance(builder3); + + // // Tamper with the accumulator + // instances = std::vector>{ accumulator, instance3 }; + // accumulator->prover_polynomials.w_l[1] = FF::random_element(); + + // // Generate a folding proof + // auto inner_folding_prover = inner_composer.create_folding_prover(instances); + // auto inner_folding_proof = inner_folding_prover.fold_instances(); + + // // Create a recursive folding verifier circuit for the folding proof of the two instances + // OuterBuilder outer_folding_circuit; + // FoldingRecursiveVerifier verifier{ &outer_folding_circuit }; + // verifier.verify_folding_proof(inner_folding_proof.folding_data); + // EXPECT_EQ(outer_folding_circuit.check_circuit(), false); + // }; }; -using FlavorTypes = testing::Types, - UltraRecursiveFlavor_>; +using FlavorTypes = testing::Types>; TYPED_TEST_SUITE(ProtoGalaxyRecursiveTests, FlavorTypes); TYPED_TEST(ProtoGalaxyRecursiveTests, InnerCircuit) @@ -387,20 +406,20 @@ TYPED_TEST(ProtoGalaxyRecursiveTests, RecursiveFoldingTest) TestFixture::test_recursive_folding(); } -TYPED_TEST(ProtoGalaxyRecursiveTests, FullProtogalaxyRecursiveTest) -{ +// TYPED_TEST(ProtoGalaxyRecursiveTests, FullProtogalaxyRecursiveTest) +// { - TestFixture::test_full_protogalaxy_recursive(); -} +// TestFixture::test_full_protogalaxy_recursive(); +// } -TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedDeciderProof) -{ - TestFixture::test_tampered_decider_proof(); -} +// TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedDeciderProof) +// { +// TestFixture::test_tampered_decider_proof(); +// } -TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedAccumulator) -{ - TestFixture::test_tampered_accumulator(); -} +// TYPED_TEST(ProtoGalaxyRecursiveTests, TamperedAccumulator) +// { +// TestFixture::test_tampered_accumulator(); +// } } // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp new file mode 100644 index 00000000000..ce9c6d3449f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp @@ -0,0 +1,44 @@ +#pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" + +namespace bb::stdlib::recursion::honk { +template struct RecursiveVerifierInstances_ { + using Flavor = Flavor_; + using Builder = typename Flavor::CircuitBuilder; + using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; + using Instance = RecursiveVerifierInstance_; + using NativeInstance = bb::VerifierInstance_; + using ArrayType = std::array, NUM_>; + + public: + static constexpr size_t NUM = NUM_; + static constexpr size_t BATCHED_EXTENDED_LENGTH = (Flavor::MAX_TOTAL_RELATION_LENGTH - 1 + NUM - 1) * (NUM - 1) + 1; + ArrayType _data; + std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } + typename ArrayType::iterator begin() { return _data.begin(); }; + typename ArrayType::iterator end() { return _data.end(); }; + Builder* builder; + // RecursiveVerifierInstances_() = default; + + RecursiveVerifierInstances_(Builder* builder, + std::shared_ptr accumulator, + std::vector> vks) + : builder(builder) + { + ASSERT(vks.size() == NUM - 1); + if (accumulator->is_accumulator) { + _data[0] = std::make_shared(builder, accumulator); + } else { + _data[0] = std::make_shared(builder, accumulator->verification_key); + } + size_t idx = 1; + for (auto vk : vks) { + _data[idx] = std::make_shared(builder, vk); + idx++; + } + } +}; +} // namespace bb::stdlib::recursion::honk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp new file mode 100644 index 00000000000..f3ae2324c12 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp @@ -0,0 +1,140 @@ +#pragma once +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/relations/relation_parameters.hpp" +#include "barretenberg/sumcheck/instance/verifier_instance.hpp" + +namespace bb::stdlib::recursion::honk { +template class RecursiveVerifierInstance_ { + public: + using FF = typename Flavor::FF; + using NativeFF = typename Flavor::Curve::ScalarFieldNative; + using Commitment = typename Flavor::Commitment; + using VerificationKey = typename Flavor::VerificationKey; + using NativeVerificationKey = typename Flavor::NativeVerificationKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using CommitmentLabels = typename Flavor::CommitmentLabels; + using RelationSeparator = typename Flavor::RelationSeparator; + using Builder = typename Flavor::CircuitBuilder; + using NativeFlavor = typename Flavor::NativeFlavor; + using VerifierInstance = bb::VerifierInstance_; + + Builder* builder; + + std::shared_ptr verification_key; + std::vector public_inputs; + size_t pub_inputs_offset = 0; + size_t public_input_size; + size_t instance_size; + size_t log_instance_size; + RelationParameters relation_parameters; + RelationSeparator alphas; + bool is_accumulator = false; + + // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). + std::vector gate_challenges; + FF target_sum; + + WitnessCommitments witness_commitments; + CommitmentLabels commitment_labels; + + RecursiveVerifierInstance_(Builder* builder) + : builder(builder){}; + RecursiveVerifierInstance_(Builder* builder, std::shared_ptr vk) + : builder(builder) + , verification_key(std::make_shared(builder, vk)) + {} + + RecursiveVerifierInstance_(Builder* builder, const std::shared_ptr& instance) + : pub_inputs_offset((instance->pub_inputs_offset)) + , public_input_size((instance->public_input_size)) + , instance_size((instance->instance_size)) + , log_instance_size((instance->log_instance_size)) + , is_accumulator(bool(instance->is_accumulator)) + { + + size_t public_input_idx = 0; + public_inputs = std::vector(public_input_size); + for (auto public_input : instance->public_inputs) { + public_inputs[public_input_idx] = FF::from_witness(builder, public_input); + } + verification_key = std::make_shared(instance_size, public_input_size); + auto other_vks = instance->verification_key->get_all(); + size_t vk_idx = 0; + for (auto& vk : verification_key->get_all()) { + vk = Commitment::from_witness(builder, other_vks[vk_idx]); + vk_idx++; + } + for (size_t alpha_idx = 0; alpha_idx < alphas.size(); alpha_idx++) { + alphas[alpha_idx] = FF::from_witness(builder, instance->alphas[alpha_idx]); + } + + auto other_comms = instance->witness_commitments.get_all(); + size_t comm_idx = 0; + for (auto& comm : witness_commitments.get_all()) { + comm = Commitment::from_witness(builder, other_comms[comm_idx]); + comm_idx++; + } + target_sum = FF::from_witness(builder, instance->target_sum); + + size_t challenge_idx = 0; + gate_challenges = std::vector(instance->gate_challenges.size()); + for (auto& challenge : gate_challenges) { + challenge = FF::from_witness(builder, instance->gate_challenges[challenge_idx]); + challenge_idx++; + } + relation_parameters.eta = FF::from_witness(builder, instance->relation_parameters.eta); + relation_parameters.beta = FF::from_witness(builder, instance->relation_parameters.beta); + relation_parameters.gamma = FF::from_witness(builder, instance->relation_parameters.gamma); + relation_parameters.public_input_delta = + FF::from_witness(builder, instance->relation_parameters.public_input_delta); + relation_parameters.lookup_grand_product_delta = + FF::from_witness(builder, instance->relation_parameters.lookup_grand_product_delta); + } + + VerifierInstance get_value() + { + VerifierInstance inst; + inst.pub_inputs_offset = pub_inputs_offset; + inst.public_input_size = public_input_size; + inst.log_instance_size = log_instance_size; + inst.instance_size = instance_size; + inst.is_accumulator = is_accumulator; + + size_t public_input_idx = 0; + inst.public_inputs = std::vector(public_input_size); + for (auto public_input : public_inputs) { + inst.public_inputs[public_input_idx] = public_input.get_value(); + } + inst.verification_key = std::make_shared(instance_size, public_input_size); + size_t vk_idx = 0; + for (auto& vk : verification_key->get_all()) { + inst.verification_key->get_all()[vk_idx] = vk.get_value(); + vk_idx++; + } + for (size_t alpha_idx = 0; alpha_idx < alphas.size(); alpha_idx++) { + inst.alphas[alpha_idx] = alphas[alpha_idx].get_value(); + } + + size_t comm_idx = 0; + for (auto& comm : witness_commitments.get_all()) { + inst.witness_commitments.get_all()[comm_idx] = comm.get_value(); + comm_idx++; + } + inst.target_sum = target_sum.get_value(); + + size_t challenge_idx = 0; + inst.gate_challenges = std::vector(gate_challenges.size()); + for (auto& challenge : inst.gate_challenges) { + challenge = gate_challenges[challenge_idx].get_value(); + challenge_idx++; + } + inst.relation_parameters.eta = relation_parameters.eta.get_value(); + inst.relation_parameters.beta = relation_parameters.beta.get_value(); + inst.relation_parameters.gamma = relation_parameters.gamma.get_value(); + inst.relation_parameters.public_input_delta = relation_parameters.public_input_delta.get_value(); + inst.relation_parameters.lookup_grand_product_delta = + relation_parameters.lookup_grand_product_delta.get_value(); + return inst; + } +}; +} // namespace bb::stdlib::recursion::honk \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp index b6e6b4edfed..47d4be24aca 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp @@ -30,14 +30,15 @@ std::array UltraRecursiveVerifier_::ve RelationParams relation_parameters; - transcript = std::make_shared(builder, proof); + StdlibProof stdlib_proof = bb::convert_proof_to_witness(builder, proof); + transcript = std::make_shared(stdlib_proof); VerifierCommitments commitments{ key }; CommitmentLabels commitment_labels; - const auto circuit_size = transcript->template receive_from_prover("circuit_size"); - const auto public_input_size = transcript->template receive_from_prover("public_input_size"); - const auto pub_inputs_offset = transcript->template receive_from_prover("pub_inputs_offset"); + const auto circuit_size = transcript->template receive_from_prover("circuit_size"); + const auto public_input_size = transcript->template receive_from_prover("public_input_size"); + const auto pub_inputs_offset = transcript->template receive_from_prover("pub_inputs_offset"); // For debugging purposes only ASSERT(static_cast(circuit_size.get_value()) == key->circuit_size); @@ -45,8 +46,7 @@ std::array UltraRecursiveVerifier_::ve std::vector public_inputs; for (size_t i = 0; i < key->num_public_inputs; ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - public_inputs.emplace_back(public_input_i); + public_inputs.emplace_back(transcript->template receive_from_prover("public_input_" + std::to_string(i))); } // Get commitments to first three wire polynomials @@ -70,7 +70,7 @@ std::array UltraRecursiveVerifier_::ve } // Get challenge for sorted list batching and wire four memory records - auto eta = transcript->get_challenge("eta"); + auto eta = transcript->template get_challenge("eta"); relation_parameters.eta = eta; // Get commitments to sorted list accumulator and fourth wire @@ -78,7 +78,7 @@ std::array UltraRecursiveVerifier_::ve commitments.w_4 = transcript->template receive_from_prover(commitment_labels.w_4); // Get permutation challenges - auto [beta, gamma] = transcript->get_challenges("beta", "gamma"); + auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial if constexpr (IsGoblinFlavor) { @@ -105,12 +105,12 @@ std::array UltraRecursiveVerifier_::ve auto sumcheck = Sumcheck(log_circuit_size, transcript); RelationSeparator alpha; for (size_t idx = 0; idx < alpha.size(); idx++) { - alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } auto gate_challenges = std::vector(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp index 5288b699452..08ab6159e90 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp @@ -17,6 +17,7 @@ template class UltraRecursiveVerifier_ { using Builder = typename Flavor::CircuitBuilder; using RelationSeparator = typename Flavor::RelationSeparator; using PairingPoints = std::array; + using Transcript = bb::BaseTranscript>; explicit UltraRecursiveVerifier_(Builder* builder, const std::shared_ptr& native_verifier_key); @@ -29,7 +30,7 @@ template class UltraRecursiveVerifier_ { std::map commitments; std::shared_ptr pcs_verification_key; Builder* builder; - std::shared_ptr> transcript; + std::shared_ptr transcript; }; // Instance declarations for Ultra and Goblin-Ultra verifier circuits with both conventional Ultra and Goblin-Ultra diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 7203a67a2c2..cef987ae9da 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -132,20 +132,21 @@ template class RecursiveVerifierTest : public testing::Te // Compute native verification key InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK // Instantiate the recursive verifier using the native verification key - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; // Spot check some values in the recursive VK to ensure it was constructed correctly - EXPECT_EQ(verifier.key->circuit_size, instance->verification_key->circuit_size); - EXPECT_EQ(verifier.key->log_circuit_size, instance->verification_key->log_circuit_size); - EXPECT_EQ(verifier.key->num_public_inputs, instance->verification_key->num_public_inputs); - EXPECT_EQ(verifier.key->q_m.get_value(), instance->verification_key->q_m); - EXPECT_EQ(verifier.key->q_r.get_value(), instance->verification_key->q_r); - EXPECT_EQ(verifier.key->sigma_1.get_value(), instance->verification_key->sigma_1); - EXPECT_EQ(verifier.key->id_3.get_value(), instance->verification_key->id_3); + EXPECT_EQ(verifier.key->circuit_size, verification_key->circuit_size); + EXPECT_EQ(verifier.key->log_circuit_size, verification_key->log_circuit_size); + EXPECT_EQ(verifier.key->num_public_inputs, verification_key->num_public_inputs); + EXPECT_EQ(verifier.key->q_m.get_value(), verification_key->q_m); + EXPECT_EQ(verifier.key->q_r.get_value(), verification_key->q_r); + EXPECT_EQ(verifier.key->sigma_1.get_value(), verification_key->sigma_1); + EXPECT_EQ(verifier.key->id_3.get_value(), verification_key->id_3); } /** @@ -160,13 +161,14 @@ template class RecursiveVerifierTest : public testing::Te // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Ultra: num gates = ", outer_circuit.num_gates); @@ -175,7 +177,7 @@ template class RecursiveVerifierTest : public testing::Te // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance); + auto native_verifier = inner_composer.create_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -192,9 +194,10 @@ template class RecursiveVerifierTest : public testing::Te // Check 3: Construct and verify a proof of the recursive verifier circuit { auto composer = get_outer_composer(); - auto instance = composer.create_instance(outer_circuit); + auto instance = composer.create_prover_instance(outer_circuit); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -216,7 +219,8 @@ template class RecursiveVerifierTest : public testing::Te // Generate a proof over the inner circuit InnerComposer inner_composer; - auto instance = inner_composer.create_instance(inner_circuit); + auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = inner_composer.compute_verification_key(instance); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); @@ -228,7 +232,7 @@ template class RecursiveVerifierTest : public testing::Te // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index db792938bd5..9f3ee582021 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp @@ -99,10 +99,14 @@ template struct VerifierInstances_ { std::shared_ptr const& operator[](size_t idx) const { return _data[idx]; } typename ArrayType::iterator begin() { return _data.begin(); }; typename ArrayType::iterator end() { return _data.end(); }; + VerifierInstances_() = default; - VerifierInstances_() + VerifierInstances_(std::vector> data) { - std::generate(_data.begin(), _data.end(), []() { return std::make_unique(); }); + ASSERT(data.size() == NUM); + for (size_t idx = 0; idx < data.size(); idx++) { + _data[idx] = std::move(data[idx]); + } }; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 3ab3a2da938..10a862ff2ce 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -30,7 +30,7 @@ template class ProverInstance_ { public: std::shared_ptr proving_key; - std::shared_ptr verification_key; + // std::shared_ptr verification_key; ProverPolynomials prover_polynomials; WitnessCommitments witness_commitments; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp index e3829102c87..09e2f41de68 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.hpp @@ -98,7 +98,7 @@ template class SumcheckProver { // This populates partially_evaluated_polynomials. auto round_univariate = round.compute_univariate(full_polynomials, relation_parameters, pow_univariate, alpha); transcript->send_to_verifier("Sumcheck:univariate_0", round_univariate); - FF round_challenge = transcript->get_challenge("Sumcheck:u_0"); + FF round_challenge = transcript->template get_challenge("Sumcheck:u_0"); multivariate_challenge.emplace_back(round_challenge); partially_evaluate(full_polynomials, multivariate_n, round_challenge); pow_univariate.partially_evaluate(round_challenge); @@ -110,7 +110,7 @@ template class SumcheckProver { round_univariate = round.compute_univariate(partially_evaluated_polynomials, relation_parameters, pow_univariate, alpha); transcript->send_to_verifier("Sumcheck:univariate_" + std::to_string(round_idx), round_univariate); - FF round_challenge = transcript->get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); multivariate_challenge.emplace_back(round_challenge); partially_evaluate(partially_evaluated_polynomials, round.round_size, round_challenge); pow_univariate.partially_evaluate(round_challenge); @@ -228,7 +228,7 @@ template class SumcheckVerifier { bool checked = round.check_sum(round_univariate); verified = verified && checked; - FF round_challenge = transcript->get_challenge("Sumcheck:u_" + std::to_string(round_idx)); + FF round_challenge = transcript->template get_challenge("Sumcheck:u_" + std::to_string(round_idx)); multivariate_challenge.emplace_back(round_challenge); round.compute_next_target_sum(round_univariate, round_challenge); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index ccb952dc19f..842152c3a14 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -69,12 +69,12 @@ TEST_F(SumcheckTests, PolynomialNormalization) auto sumcheck = SumcheckProver(multivariate_n, transcript); RelationSeparator alpha; for (size_t idx = 0; idx < alpha.size(); idx++) { - alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } std::vector gate_challenges(multivariate_d); for (size_t idx = 0; idx < multivariate_d; idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); @@ -141,12 +141,12 @@ TEST_F(SumcheckTests, Prover) RelationSeparator alpha; for (size_t idx = 0; idx < alpha.size(); idx++) { - alpha[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + alpha[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } std::vector gate_challenges(multivariate_d); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto output = sumcheck.prove(full_polynomials, {}, alpha, gate_challenges); FF u_0 = output.challenge[0]; @@ -224,12 +224,12 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) RelationSeparator prover_alpha; for (size_t idx = 0; idx < prover_alpha.size(); idx++) { - prover_alpha[idx] = prover_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + prover_alpha[idx] = prover_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } std::vector prover_gate_challenges(multivariate_d); for (size_t idx = 0; idx < multivariate_d; idx++) { prover_gate_challenges[idx] = - prover_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + prover_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto output = sumcheck_prover.prove(full_polynomials, {}, prover_alpha, prover_gate_challenges); @@ -238,12 +238,13 @@ TEST_F(SumcheckTests, ProverAndVerifierSimple) auto sumcheck_verifier = SumcheckVerifier(multivariate_d, verifier_transcript); RelationSeparator verifier_alpha; for (size_t idx = 0; idx < verifier_alpha.size(); idx++) { - verifier_alpha[idx] = verifier_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + verifier_alpha[idx] = + verifier_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } std::vector verifier_gate_challenges(multivariate_d); for (size_t idx = 0; idx < multivariate_d; idx++) { verifier_gate_challenges[idx] = - verifier_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + verifier_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto verifier_output = sumcheck_verifier.verify(relation_parameters, verifier_alpha, verifier_gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp index 5b39412ac11..655641144b3 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.hpp @@ -6,6 +6,9 @@ #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/ecc/fields/field_conversion.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" +#include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/primitives/field/field_conversion.hpp" // #define LOG_CHALLENGES // #define LOG_INTERACTIONS @@ -58,15 +61,39 @@ class TranscriptManifest { bool operator==(const TranscriptManifest& other) const = default; }; +struct NativeTranscriptParams { + using Fr = bb::fr; + using Proof = HonkProof; + static inline Fr hash(const std::vector& data) + { + return crypto::Poseidon2::hash(data); + } + template static inline T convert_challenge(const Fr& challenge) + { + return bb::field_conversion::convert_challenge(challenge); + } + template static constexpr size_t calc_num_bn254_frs() + { + return bb::field_conversion::calc_num_bn254_frs(); + } + template static inline T convert_from_bn254_frs(std::span frs) + { + return bb::field_conversion::convert_from_bn254_frs(frs); + } + template static inline std::vector convert_to_bn254_frs(const T& element) + { + return bb::field_conversion::convert_to_bn254_frs(element); + } +}; + /** * @brief Common transcript class for both parties. Stores the data for the current round, as well as the * manifest. */ -class BaseTranscript { +template class BaseTranscript { public: - using Fr = bb::fr; - using Poseidon2Params = crypto::Poseidon2Bn254ScalarFieldParams; - using Proof = HonkProof; + using Fr = typename TranscriptParams::Fr; + using Proof = typename TranscriptParams::Proof; BaseTranscript() = default; @@ -78,6 +105,7 @@ class BaseTranscript { explicit BaseTranscript(const Proof& proof_data) : proof_data(proof_data.begin(), proof_data.end()) {} + static constexpr size_t HASH_OUTPUT_SIZE = 32; std::ptrdiff_t proof_start = 0; @@ -132,7 +160,7 @@ class BaseTranscript { // Hash the full buffer with poseidon2, which is believed to be a collision resistant hash function and a random // oracle, removing the need to pre-hash to compress and then hash with a random oracle, as we previously did // with Pedersen and Blake3s. - Fr base_hash = crypto::Poseidon2::hash(full_buffer); + Fr base_hash = TranscriptParams::hash(full_buffer); Fr new_challenge = base_hash; // update previous challenge buffer for next time we call this function @@ -167,7 +195,7 @@ class BaseTranscript { */ template void serialize_to_buffer(const T& element, Proof& proof_data) { - auto element_frs = bb::field_conversion::convert_to_bn254_frs(element); + auto element_frs = TranscriptParams::template convert_to_bn254_frs(element); proof_data.insert(proof_data.end(), element_frs.begin(), element_frs.end()); } /** @@ -181,13 +209,13 @@ class BaseTranscript { */ template T deserialize_from_buffer(const Proof& proof_data, size_t& offset) const { - constexpr size_t element_fr_size = bb::field_conversion::calc_num_bn254_frs(); + constexpr size_t element_fr_size = TranscriptParams::template calc_num_bn254_frs(); ASSERT(offset + element_fr_size <= proof_data.size()); auto element_frs = std::span{ proof_data }.subspan(offset, element_fr_size); offset += element_fr_size; - auto element = bb::field_conversion::convert_from_bn254_frs(element_frs); + auto element = TranscriptParams::template convert_from_bn254_frs(element_frs); return element; } @@ -225,7 +253,8 @@ class BaseTranscript { * @param labels human-readable names for the challenges for the manifest * @return std::array challenges for this round. */ - template std::array get_challenges(const Strings&... labels) + template + std::array get_challenges(const Strings&... labels) { constexpr size_t num_challenges = sizeof...(Strings); @@ -235,7 +264,7 @@ class BaseTranscript { // Compute the new challenge buffer from which we derive the challenges. // Create challenges from Frs. - std::array challenges{}; + std::array challenges{}; // Generate the challenges by iteratively hashing over the previous challenge. for (size_t i = 0; i < num_challenges; i++) { @@ -247,10 +276,10 @@ class BaseTranscript { // copy half of the hash to lower 128 bits of challenge Note: because of how read() from buffers to fields works (in field_declarations.hpp), we use the later half of the buffer // std::copy_n(next_challenge_buffer.begin(), - HASH_OUTPUT_SIZE / 2, - field_element_buffer.begin() + HASH_OUTPUT_SIZE / 2); + // HASH_OUTPUT_SIZE / 2, + // field_element_buffer.begin() + HASH_OUTPUT_SIZE / 2); */ - challenges[i] = static_cast(get_next_challenge_buffer()); + challenges[i] = TranscriptParams::template convert_challenge(get_next_challenge_buffer()); } // Prepare for next round. @@ -278,7 +307,7 @@ class BaseTranscript { // TODO(Adrian): Consider restricting serialization (via concepts) to types T for which sizeof(T) reliably // returns the size of T in frs. (E.g. this is true for std::array but not for std::vector). // convert element to field elements - auto element_frs = bb::field_conversion::convert_to_bn254_frs(element); + auto element_frs = TranscriptParams::convert_to_bn254_frs(element); proof_data.insert(proof_data.end(), element_frs.begin(), element_frs.end()); #ifdef LOG_INTERACTIONS @@ -297,7 +326,7 @@ class BaseTranscript { */ template T receive_from_prover(const std::string& label) { - constexpr size_t element_size = bb::field_conversion::calc_num_bn254_frs(); + const size_t element_size = TranscriptParams::template calc_num_bn254_frs(); ASSERT(num_frs_read + element_size <= proof_data.size()); auto element_frs = std::span{ proof_data }.subspan(num_frs_read, element_size); @@ -305,7 +334,7 @@ class BaseTranscript { BaseTranscript::consume_prover_element_frs(label, element_frs); - auto element = bb::field_conversion::convert_from_bn254_frs(element_frs); + auto element = TranscriptParams::template convert_from_bn254_frs(element_frs); #ifdef LOG_INTERACTIONS if constexpr (Loggable) { @@ -339,13 +368,13 @@ class BaseTranscript { static std::shared_ptr verifier_init_empty(const std::shared_ptr& transcript) { auto verifier_transcript = std::make_shared(transcript->proof_data); - [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover("Init"); + [[maybe_unused]] auto _ = verifier_transcript->template receive_from_prover("Init"); return verifier_transcript; }; - uint256_t get_challenge(const std::string& label) + template ChallengeType get_challenge(const std::string& label) { - uint256_t result = get_challenges(label)[0]; + ChallengeType result = get_challenges(label)[0]; #if defined LOG_CHALLENGES || defined LOG_INTERACTIONS info("challenge: ", label, ": ", result); #endif @@ -357,15 +386,16 @@ class BaseTranscript { void print() { manifest.print(); } }; -/** - * @brief Convert an array of uint256_t's to an array of field elements - * @details The syntax `std::array [a, b] = transcript.get_challenges("a", "b")` is unfortunately not allowed - * (structured bindings must be defined with auto return type), so we need a workaround. - */ -template std::array challenges_to_field_elements(std::array&& arr) +template +static bb::StdlibProof convert_proof_to_witness(Builder* builder, const HonkProof& proof) { - std::array result; - std::move(arr.begin(), arr.end(), result.begin()); + bb::StdlibProof result; + for (const auto& element : proof) { + result.push_back(bb::stdlib::witness_t(builder, element)); + } return result; } + +using NativeTranscript = BaseTranscript; + } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp index 2d70ad4a24f..2301e92cadb 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp @@ -1,18 +1,18 @@ -#include "barretenberg/transcript/transcript.hpp" +#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" #include using namespace bb; -using FF = fr; -using Fr = fr; -using Fq = fq; -using Transcript = BaseTranscript; +using FF = bb::fr; +using Fr = bb::fr; +using Fq = bb::fq; +using Transcript = NativeTranscript; /** * @brief Test sending, receiving, and exporting proofs * */ -TEST(BaseTranscript, TwoProversTwoFields) +TEST(NativeTranscript, TwoProversTwoFields) { const auto EXPECT_STATE = [](const Transcript& transcript, size_t start, size_t written, size_t read) { EXPECT_EQ(transcript.proof_start, static_cast(start)); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp index 9117a03a405..5e033178cba 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp @@ -19,7 +19,7 @@ class GoblinTranslatorComposer { using CommitmentKey = typename Flavor::CommitmentKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using Polynomial = typename Flavor::Polynomial; - using Transcript = BaseTranscript; + using Transcript = NativeTranscript; static constexpr std::string_view NAME_STRING = "GoblinTranslator"; static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp index 05850f7366a..0bd890ccd34 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp @@ -63,7 +63,7 @@ TEST_F(GoblinTranslatorComposerTests, Basic) auto prover_transcript = std::make_shared(); prover_transcript->send_to_verifier("init", Fq::random_element()); prover_transcript->export_proof(); - Fq translation_batching_challenge = prover_transcript->get_challenge("Translation:batching_challenge"); + Fq translation_batching_challenge = prover_transcript->template get_challenge("Translation:batching_challenge"); Fq translation_evaluation_challenge = Fq::random_element(); auto circuit_builder = CircuitBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); EXPECT_TRUE(circuit_builder.check_circuit()); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index e6b1e89a963..11a557a1b98 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -88,7 +88,7 @@ void GoblinTranslatorProver::execute_wire_and_sorted_constraints_commitments_rou void GoblinTranslatorProver::execute_grand_product_computation_round() { // Compute and store parameters required by relations in Sumcheck - FF gamma = transcript->get_challenge("gamma"); + FF gamma = transcript->template get_challenge("gamma"); const size_t NUM_LIMB_BITS = Flavor::NUM_LIMB_BITS; relation_parameters.beta = 0; relation_parameters.gamma = gamma; @@ -140,10 +140,10 @@ void GoblinTranslatorProver::execute_relation_check_rounds() using Sumcheck = SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp index 4db4f131385..c46545707ba 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp @@ -27,11 +27,11 @@ class GoblinTranslatorProver { const std::shared_ptr& commitment_key, const std::shared_ptr& transcript = std::make_shared()); - BBERG_PROFILE void execute_preamble_round(); - BBERG_PROFILE void execute_wire_and_sorted_constraints_commitments_round(); - BBERG_PROFILE void execute_grand_product_computation_round(); - BBERG_PROFILE void execute_relation_check_rounds(); - BBERG_PROFILE void execute_zeromorph_rounds(); + BB_PROFILE void execute_preamble_round(); + BB_PROFILE void execute_wire_and_sorted_constraints_commitments_round(); + BB_PROFILE void execute_grand_product_computation_round(); + BB_PROFILE void execute_relation_check_rounds(); + BB_PROFILE void execute_zeromorph_rounds(); HonkProof& export_proof(); HonkProof& construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp index 6165e4f99d9..2eb78673a02 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -64,7 +64,7 @@ void GoblinTranslatorVerifier::put_translation_data_in_relation_parameters(const */ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) { - batching_challenge_v = transcript->get_challenge("Translation:batching_challenge"); + batching_challenge_v = transcript->template get_challenge("Translation:batching_challenge"); transcript->load_proof(proof); Flavor::VerifierCommitments commitments{ key }; @@ -229,7 +229,7 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) commitments.ordered_range_constraints_4 = receive_commitment(commitment_labels.ordered_range_constraints_4); // Get permutation challenges - FF gamma = transcript->get_challenge("gamma"); + FF gamma = transcript->template get_challenge("gamma"); relation_parameters.beta = 0; relation_parameters.gamma = gamma; @@ -242,10 +242,10 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index bbec6530151..d8759ba07a0 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -84,10 +84,11 @@ TEST_F(DataBusComposerTests, CallDataRead) auto composer = GoblinUltraComposer(); // Construct and verify Honk proof - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); // For debugging, use "instance_inspector::print_databus_info(instance)" + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_TRUE(verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index 6c948a15e2f..ef4938a5851 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -23,6 +23,8 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { using FF = Curve::ScalarField; using Point = Curve::AffineElement; using CommitmentKey = bb::CommitmentKey; + using MergeProver = MergeProver_; + using MergeVerifier = MergeVerifier_; /** * @brief Generate a simple test circuit with some ECC op gates and conventional arithmetic gates @@ -60,9 +62,10 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { */ bool construct_and_verify_honk_proof(auto& composer, auto& builder) { - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index a557b138dae..6190d640ac1 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -145,7 +145,7 @@ TEST_F(GoblinUltraTranscriptTests, ProverManifestConsistency) // Automatically generate a transcript manifest by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); @@ -172,12 +172,13 @@ TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) // Automatically generate a transcript manifest in the prover by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -201,7 +202,7 @@ TEST_F(GoblinUltraTranscriptTests, ChallengeGenerationTest) // initialized with random value sent to verifier auto transcript = Flavor::Transcript::prover_init_empty(); // test a bunch of challenges - auto challenges = transcript->get_challenges("a", "b", "c", "d", "e", "f"); + auto challenges = transcript->template get_challenges("a", "b", "c", "d", "e", "f"); // check they are not 0 for (size_t i = 0; i < challenges.size(); ++i) { ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; @@ -209,7 +210,7 @@ TEST_F(GoblinUltraTranscriptTests, ChallengeGenerationTest) constexpr uint32_t random_val{ 17 }; // arbitrary transcript->send_to_verifier("random val", random_val); // test more challenges - auto [a, b, c] = challenges_to_field_elements(transcript->get_challenges("a", "b", "c")); + auto [a, b, c] = transcript->template get_challenges("a", "b", "c"); ASSERT_NE(a, 0) << "Challenge a is 0"; ASSERT_NE(b, 0) << "Challenge b is 0"; ASSERT_NE(c, 0) << "Challenge c is 0"; @@ -223,10 +224,11 @@ TEST_F(GoblinUltraTranscriptTests, StructureTest) // Automatically generate a transcript manifest by constructing a proof auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp index 8d39901d419..721830fadd2 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.cpp @@ -8,7 +8,8 @@ namespace bb { * per-circuit contribution t_i^{shift} * */ -MergeProver::MergeProver(const std::shared_ptr& op_queue) +template +MergeProver_::MergeProver_(const std::shared_ptr& op_queue) : op_queue(op_queue) , pcs_commitment_key(std::make_shared(op_queue->ultra_ops[0].size())) { @@ -29,7 +30,7 @@ MergeProver::MergeProver(const std::shared_ptr& op_queue) * * @return honk::proof */ -HonkProof MergeProver::construct_proof() +template HonkProof MergeProver_::construct_proof() { transcript = std::make_shared(); @@ -69,7 +70,7 @@ HonkProof MergeProver::construct_proof() // Compute evaluations T_i(\kappa), T_{i-1}(\kappa), t_i^{shift}(\kappa), add to transcript. For each polynomial // we add a univariate opening claim {p(X), (\kappa, p(\kappa))} to the set of claims to be checked via batched KZG. - FF kappa = transcript->get_challenge("kappa"); + FF kappa = transcript->template get_challenge("kappa"); // Add univariate opening claims for each polynomial. std::vector opening_claims; @@ -94,7 +95,7 @@ HonkProof MergeProver::construct_proof() opening_claims.emplace_back(OpeningClaim{ polynomial, { kappa, evaluation } }); } - FF alpha = transcript->get_challenge("alpha"); + FF alpha = transcript->template get_challenge("alpha"); // Construct batched polynomial to opened via KZG auto batched_polynomial = Polynomial(N); @@ -117,4 +118,7 @@ HonkProof MergeProver::construct_proof() return transcript->proof_data; } +template class MergeProver_; +template class MergeProver_; + } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp index a615f9f816c..c4002403382 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_prover.hpp @@ -13,22 +13,23 @@ namespace bb { * @brief Prover class for the Goblin ECC op queue transcript merge protocol * */ -class MergeProver { - using Curve = curve::BN254; - using FF = Curve::ScalarField; - using Polynomial = polynomial; - using CommitmentKey = bb::CommitmentKey; - using Commitment = Curve::AffineElement; - using PCS = bb::KZG; - using OpeningClaim = typename bb::ProverOpeningClaim; - using Transcript = BaseTranscript; +template class MergeProver_ { + using FF = typename Flavor::FF; + using Polynomial = typename Flavor::Polynomial; + using CommitmentKey = typename Flavor::CommitmentKey; + using Commitment = typename Flavor::Commitment; + using PCS = typename Flavor::PCS; + using Curve = typename Flavor::Curve; + using OpeningClaim = ProverOpeningClaim; + using OpeningPair = bb::OpeningPair; + using Transcript = NativeTranscript; public: std::shared_ptr transcript; - explicit MergeProver(const std::shared_ptr&); + explicit MergeProver_(const std::shared_ptr&); - BBERG_PROFILE HonkProof construct_proof(); + BB_PROFILE HonkProof construct_proof(); private: std::shared_ptr op_queue; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index f8eb261b195..e0ade5f34be 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -2,8 +2,10 @@ namespace bb { -MergeVerifier::MergeVerifier() - : pcs_verification_key(std::make_unique(0, bb::srs::get_crs_factory())){}; +template +MergeVerifier_::MergeVerifier_() + : transcript(std::make_shared()) + , pcs_verification_key(std::make_unique(0, bb::srs::get_crs_factory())){}; /** * @brief Verify proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4. @@ -13,34 +15,35 @@ MergeVerifier::MergeVerifier() * M_{i-1}), where the shift magnitude M_{i-1} is the length of T_{i-1}. This protocol verfies that the aggregate op * queue has been constructed correctly via a simple Schwartz-Zippel check. Evaluations are checked via batched KZG. * + * @tparam Flavor * @return HonkProof& */ -bool MergeVerifier::verify_proof(const HonkProof& proof) +template bool MergeVerifier_::verify_proof(const HonkProof& proof) { transcript = std::make_shared(proof); // Receive commitments [t_i^{shift}], [T_{i-1}], and [T_i] - std::array C_T_prev; - std::array C_t_shift; - std::array C_T_current; - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { + std::array C_T_prev; + std::array C_t_shift; + std::array C_T_current; + for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { C_T_prev[idx] = transcript->template receive_from_prover("T_PREV_" + std::to_string(idx + 1)); C_t_shift[idx] = transcript->template receive_from_prover("t_SHIFT_" + std::to_string(idx + 1)); C_T_current[idx] = transcript->template receive_from_prover("T_CURRENT_" + std::to_string(idx + 1)); } - FF kappa = transcript->get_challenge("kappa"); + FF kappa = transcript->template get_challenge("kappa"); // Receive transcript poly evaluations and add corresponding univariate opening claims {(\kappa, p(\kappa), [p(X)]} - std::array T_prev_evals; - std::array t_shift_evals; - std::array T_current_evals; + std::array T_prev_evals; + std::array t_shift_evals; + std::array T_current_evals; std::vector opening_claims; - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { T_prev_evals[idx] = transcript->template receive_from_prover("T_prev_eval_" + std::to_string(idx + 1)); opening_claims.emplace_back(OpeningClaim{ { kappa, T_prev_evals[idx] }, C_T_prev[idx] }); } - for (size_t idx = 0; idx < NUM_WIRES; ++idx) { + for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { t_shift_evals[idx] = transcript->template receive_from_prover("t_shift_eval_" + std::to_string(idx + 1)); opening_claims.emplace_back(OpeningClaim{ { kappa, t_shift_evals[idx] }, C_t_shift[idx] }); } @@ -56,7 +59,7 @@ bool MergeVerifier::verify_proof(const HonkProof& proof) identity_checked = identity_checked && (T_current_evals[idx] == T_prev_evals[idx] + t_shift_evals[idx]); } - FF alpha = transcript->get_challenge("alpha"); + FF alpha = transcript->template get_challenge("alpha"); // Construct batched commitment and evaluation from constituents auto batched_commitment = opening_claims[0].commitment; @@ -76,4 +79,7 @@ bool MergeVerifier::verify_proof(const HonkProof& proof) return identity_checked && verified; } +template class MergeVerifier_; +template class MergeVerifier_; + } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp index efd95773b6f..38749c1347f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.hpp @@ -14,19 +14,19 @@ namespace bb { * @brief Verifier class for the Goblin ECC op queue transcript merge protocol * */ -class MergeVerifier { - using Curve = curve::BN254; +template class MergeVerifier_ { + using Curve = typename Flavor::Curve; using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using PCS = bb::KZG; using OpeningClaim = bb::OpeningClaim; using VerifierCommitmentKey = bb::VerifierCommitmentKey; - using Transcript = BaseTranscript; + using Transcript = NativeTranscript; public: std::shared_ptr transcript; - explicit MergeVerifier(); + explicit MergeVerifier_(); bool verify_proof(const HonkProof& proof); private: diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index f0237d439f1..c060f3cc60c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -14,9 +14,11 @@ template class ProtoGalaxyTests : public testing::Test { public: using Composer = UltraComposer_; using VerificationKey = typename Flavor::VerificationKey; - using Instance = ProverInstance_; - using Instances = ProverInstances_; - using ProtoGalaxyProver = ProtoGalaxyProver_; + using ProverInstance = ProverInstance_; + using ProverInstances = ProverInstances_; + using VerifierInstance = VerifierInstance_; + using VerifierInstances = VerifierInstances_; + using ProtoGalaxyProver = ProtoGalaxyProver_; using FF = typename Flavor::FF; using Affine = typename Flavor::Commitment; using Projective = typename Flavor::GroupElement; @@ -59,21 +61,20 @@ template class ProtoGalaxyTests : public testing::Test { return full_polynomials; } - static std::shared_ptr fold_and_verify(const std::vector>& instances, - Composer& composer, - bool expected_result) + static std::tuple, std::shared_ptr> fold_and_verify( + const std::vector>& prover_instances, + const std::vector>& verifier_instances, + Composer& composer) { - auto folding_prover = composer.create_folding_prover(instances); - auto folding_verifier = composer.create_folding_verifier(); - - auto proof = folding_prover.fold_instances(); - auto next_accumulator = proof.accumulator; - auto res = folding_verifier.verify_folding_proof(proof.folding_data); - EXPECT_EQ(res, expected_result); - return next_accumulator; + auto folding_prover = composer.create_folding_prover(prover_instances); + auto folding_verifier = composer.create_folding_verifier(verifier_instances); + + auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); + auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); + return { prover_accumulator, verifier_accumulator }; } - static void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) + static void check_accumulator_target_sum_manual(std::shared_ptr& accumulator, bool expected_result) { auto instance_size = accumulator->instance_size; auto expected_honk_evals = ProtoGalaxyProver::compute_full_honk_evaluations( @@ -90,10 +91,13 @@ template class ProtoGalaxyTests : public testing::Test { EXPECT_EQ(accumulator->target_sum == expected_target_sum, expected_result); } - static void decide_and_verify(std::shared_ptr& accumulator, Composer& composer, bool expected_result) + static void decide_and_verify(std::shared_ptr& prover_accumulator, + std::shared_ptr& verifier_accumulator, + Composer& composer, + bool expected_result) { - auto decider_prover = composer.create_decider_prover(accumulator); - auto decider_verifier = composer.create_decider_verifier(accumulator); + auto decider_prover = composer.create_decider_prover(prover_accumulator); + auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); auto decider_proof = decider_prover.construct_proof(); auto verified = decider_verifier.verify_proof(decider_proof); EXPECT_EQ(verified, expected_result); @@ -101,8 +105,8 @@ template class ProtoGalaxyTests : public testing::Test { /** * @brief For a valid circuit, ensures that computing the value of the full UH/UGH relation at each row in its - * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of Goblin) - * will be 0. + * execution trace (with the contribution of the linearly dependent one added tot he first row, in case of + * Goblin) will be 0. * */ static void test_full_honk_evaluations_valid_circuit() @@ -111,7 +115,7 @@ template class ProtoGalaxyTests : public testing::Test { construct_circuit(builder); auto composer = Composer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); instance->initialize_prover_polynomials(); auto eta = FF::random_element(); @@ -136,8 +140,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the same - * as if computed manually. + * @brief Check the coefficients of the perturbator computed from dummy \vec{β}, \vec{δ} and f_i(ω) will be the + * same as if computed manually. * */ static void test_pertubator_coefficients() @@ -191,7 +195,7 @@ template class ProtoGalaxyTests : public testing::Test { target_sum += full_honk_evals[i] * pow_beta[i]; } - auto accumulator = std::make_shared(); + auto accumulator = std::make_shared(); accumulator->prover_polynomials = std::move(full_polynomials); accumulator->gate_challenges = betas; accumulator->target_sum = target_sum; @@ -206,8 +210,8 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner and - * check them against the evaluations returned by the function. + * @brief Manually compute the expected evaluations of the combiner quotient, given evaluations of the combiner + * and check them against the evaluations returned by the function. * */ static void test_combiner_quotient() @@ -239,25 +243,22 @@ template class ProtoGalaxyTests : public testing::Test { } /** - * @brief For two dummy instances with their relation parameter η set, check that combining them in a univariate, - * barycentrially extended to the desired number of evaluations, is performed correctly. + * @brief For two dummy instances with their relation parameter η set, check that combining them in a + * univariate, barycentrially extended to the desired number of evaluations, is performed correctly. * */ static void test_combine_relation_parameters() { - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; - Builder builder1; - auto instance1 = std::make_shared(builder1); + auto instance1 = std::make_shared(builder1); instance1->relation_parameters.eta = 1; Builder builder2; builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); + auto instance2 = std::make_shared(builder2); instance2->relation_parameters.eta = 3; - Instances instances{ { instance1, instance2 } }; + ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_relation_parameters(instances); bb::Univariate expected_eta{ { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 } }; @@ -270,19 +271,16 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_combine_alpha() { - using Instances = ProverInstances_; - using Instance = typename Instances::Instance; - Builder builder1; - auto instance1 = std::make_shared(builder1); + auto instance1 = std::make_shared(builder1); instance1->alphas.fill(2); Builder builder2; builder2.add_variable(3); - auto instance2 = std::make_shared(builder2); + auto instance2 = std::make_shared(builder2); instance2->alphas.fill(4); - Instances instances{ { instance1, instance2 } }; + ProverInstances instances{ { instance1, instance2 } }; ProtoGalaxyProver::combine_alpha(instances); bb::Univariate expected_alpha{ { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26 } }; @@ -301,26 +299,29 @@ template class ProtoGalaxyTests : public testing::Test { auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); + + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - instances = std::vector>{ first_accumulator, instance_3 }; - auto second_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(second_accumulator, true); + check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(first_accumulator, composer, true); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, true); } /** @@ -330,67 +331,67 @@ template class ProtoGalaxyTests : public testing::Test { static void test_tampered_commitment() { auto composer = Composer(); - auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + check_accumulator_target_sum_manual(prover_accumulator, true); - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); - + verifier_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); - // tampering with the commitment should cause the decider to fail - first_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); - instances = std::vector>{ first_accumulator, instance_3 }; + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - auto second_accumulator = fold_and_verify(instances, composer, true); + check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(second_accumulator, composer, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); } /** - * @brief Ensure tampering an accumulator and then calling fold again causes both the folding verification and - * decider verification to fail. + * @brief Ensure tampering an accumulator and then calling fold again causes the target sums in the prover and + * verifier accumulators to be different and decider verification to fail. * */ static void test_tampered_accumulator_polynomial() { auto composer = Composer(); - auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto instance_1 = composer.create_instance(builder_1); + auto prover_instance_1 = composer.create_prover_instance(builder_1); + auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); - - auto instance_2 = composer.create_instance(builder_2); - - auto instances = std::vector>{ instance_1, instance_2 }; - auto first_accumulator = fold_and_verify(instances, composer, true); - check_accumulator_target_sum_manual(first_accumulator, true); + auto prover_instance_2 = composer.create_prover_instance(builder_2); + auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify( + { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto instance_3 = composer.create_instance(builder_3); + auto prover_instance_3 = composer.create_prover_instance(builder_3); + auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); - // tampering with accumulator's polynomial should cause both folding and deciding to fail - instances = std::vector>{ first_accumulator, instance_3 }; - first_accumulator->prover_polynomials.w_l[1] = FF::random_element(); - auto second_accumulator = fold_and_verify(instances, composer, false); + prover_accumulator->prover_polynomials.w_l[1] = FF::random_element(); + auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( + { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); - decide_and_verify(second_accumulator, composer, false); + EXPECT_EQ(prover_accumulator_2->target_sum == verifier_accumulator_2->target_sum, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); } }; } // namespace diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp index 2b5ec50f37e..a52bbbe240b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -268,7 +268,7 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) // Create a prover (it will compute proving key and witness) auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; @@ -321,7 +321,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) // Create a prover (it will compute proving key and witness) auto composer = GoblinUltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 2f736f2ed82..34515508931 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -149,7 +149,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) // Create a prover (it will compute proving key and witness) auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); // Generate eta, beta and gamma FF eta = FF::random_element(); @@ -166,7 +166,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) RelationSeparator prover_alphas; for (size_t idx = 0; idx < prover_alphas.size(); idx++) { - prover_alphas[idx] = prover_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + prover_alphas[idx] = prover_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } instance->alphas = prover_alphas; @@ -174,7 +174,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) std::vector prover_gate_challenges(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { prover_gate_challenges[idx] = - prover_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + prover_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } instance->gate_challenges = prover_gate_challenges; auto prover_output = sumcheck_prover.prove(instance); @@ -184,13 +184,13 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) auto sumcheck_verifier = SumcheckVerifier(log_circuit_size, verifier_transcript); RelationSeparator verifier_alphas; for (size_t idx = 0; idx < verifier_alphas.size(); idx++) { - verifier_alphas[idx] = verifier_transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + verifier_alphas[idx] = verifier_transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } std::vector verifier_gate_challenges(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { verifier_gate_challenges[idx] = - verifier_transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + verifier_transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto verifier_output = sumcheck_verifier.verify(instance->relation_parameters, verifier_alphas, verifier_gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp index ae42bd4366a..b745f001c5b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -12,12 +12,9 @@ namespace bb { * @return Pointer to the resulting verification key of the Instance. * */ template -void UltraComposer_::compute_verification_key(const std::shared_ptr>& instance) +std::shared_ptr UltraComposer_::compute_verification_key( + const std::shared_ptr>& instance) { - if (instance->verification_key) { - return; - } - auto& proving_key = instance->proving_key; auto verification_key = @@ -61,23 +58,31 @@ void UltraComposer_::compute_verification_key(const std::shared_ptrq_poseidon2_internal = commitment_key->commit(proving_key->q_poseidon2_internal); } - instance->verification_key = std::move(verification_key); + return std::move(verification_key); } template -std::shared_ptr> UltraComposer_::create_instance(CircuitBuilder& circuit) +std::shared_ptr> UltraComposer_::create_prover_instance(CircuitBuilder& circuit) { circuit.add_gates_to_ensure_all_polys_are_non_zero(); circuit.finalize_circuit(); - auto instance = std::make_shared(circuit); - commitment_key = compute_commitment_key(instance->proving_key->circuit_size); + auto instance = std::make_shared(circuit); + instance->instance_size = instance->proving_key->circuit_size; + commitment_key = compute_commitment_key(instance->instance_size); // hm + return instance; +} - compute_verification_key(instance); +template +std::shared_ptr> UltraComposer_::create_verifier_instance( + std::shared_ptr>& prover_instance) +{ + auto instance = std::make_shared(); + instance->verification_key = compute_verification_key(prover_instance); return instance; } template -UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, +UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, const std::shared_ptr& transcript) { UltraProver_ output_state(instance, commitment_key, transcript); @@ -86,10 +91,9 @@ UltraProver_ UltraComposer_::create_prover(const std::shared_ptr } template -UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& instance, +UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& verification_key, const std::shared_ptr& transcript) { - auto& verification_key = instance->verification_key; UltraVerifier_ output_state(transcript, verification_key); auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); output_state.pcs_verification_key = std::move(pcs_verification_key); @@ -98,7 +102,7 @@ UltraVerifier_ UltraComposer_::create_verifier(const std::shared } template -DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, +DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { commitment_key = compute_commitment_key(accumulator->instance_size); @@ -109,7 +113,7 @@ DeciderProver_ UltraComposer_::create_decider_prover(const std:: template DeciderProver_ UltraComposer_::create_decider_prover( - const std::shared_ptr& accumulator, + const std::shared_ptr& accumulator, const std::shared_ptr& commitment_key, const std::shared_ptr& transcript) { @@ -119,11 +123,10 @@ DeciderProver_ UltraComposer_::create_decider_prover( } template -DeciderVerifier_ UltraComposer_::create_decider_verifier(const std::shared_ptr& accumulator, - const std::shared_ptr& transcript) +DeciderVerifier_ UltraComposer_::create_decider_verifier( + const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { - auto& verification_key = accumulator->verification_key; - DeciderVerifier_ output_state(transcript, verification_key); + DeciderVerifier_ output_state(transcript, accumulator); auto pcs_verification_key = std::make_unique(accumulator->instance_size, crs_factory_); output_state.pcs_verification_key = std::move(pcs_verification_key); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index ea929b92033..7738709b7f6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -20,7 +20,7 @@ template class UltraComposer_ { using CommitmentKey = typename Flavor::CommitmentKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using ProverInstance = ProverInstance_; - using Instance = ProverInstance; + using VerifierInstance = VerifierInstance_; using FF = typename Flavor::FF; using Transcript = typename Flavor::Transcript; using CRSFactory = srs::factories::CrsFactory; @@ -57,41 +57,49 @@ template class UltraComposer_ { return commitment_key; }; - std::shared_ptr create_instance(CircuitBuilder& circuit); + std::shared_ptr create_prover_instance(CircuitBuilder&); - UltraProver_ create_prover(const std::shared_ptr&, + /** + * @brief Create a verifier instance object. + * + * @details Currently use prover instance + */ + std::shared_ptr create_verifier_instance(std::shared_ptr&); + + UltraProver_ create_prover(const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); UltraVerifier_ create_verifier( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderProver_ create_decider_prover( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderProver_ create_decider_prover( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); DeciderVerifier_ create_decider_verifier( - const std::shared_ptr&, + const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); UltraVerifier_ create_verifier(CircuitBuilder& circuit); UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); - ProtoGalaxyProver_ create_folding_prover(const std::vector>& instances) + ProtoGalaxyProver_ create_folding_prover( + const std::vector>& instances) { ProtoGalaxyProver_ output_state(instances, commitment_key); return output_state; }; - ProtoGalaxyVerifier_ create_folding_verifier() - { - auto insts = VerifierInstances(); - ProtoGalaxyVerifier_ output_state(insts); + ProtoGalaxyVerifier_ create_folding_verifier( + const std::vector>& instances) + { + ProtoGalaxyVerifier_ output_state(instances); return output_state; }; @@ -101,7 +109,7 @@ template class UltraComposer_ { * * @param inst */ - void compute_verification_key(const std::shared_ptr&); + std::shared_ptr compute_verification_key(const std::shared_ptr&); }; // TODO(#532): this pattern is weird; is this not instantiating the templates? diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 205a67aad24..514b2b69783 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -33,9 +33,10 @@ std::vector add_variables(auto& circuit_builder, std::vector v void prove_and_verify(auto& circuit_builder, auto& composer, bool expected_result) { - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_EQ(verified, expected_result); @@ -67,7 +68,7 @@ TEST_F(UltraHonkComposerTests, ANonZeroPolynomialIsAGoodPolynomial) auto circuit_builder = UltraCircuitBuilder(); auto composer = UltraComposer(); - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); auto proving_key = instance->proving_key; @@ -198,9 +199,10 @@ TEST_F(UltraHonkComposerTests, create_gates_from_plookup_accumulators) } } auto composer = UltraComposer(); - auto instance = composer.create_instance(circuit_builder); + auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool result = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index 16118067408..27acb7dd432 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -91,7 +91,7 @@ template void UltraProver_::execute_wire_commitme */ template void UltraProver_::execute_sorted_list_accumulator_round() { - FF eta = transcript->get_challenge("eta"); + FF eta = transcript->template get_challenge("eta"); instance->compute_sorted_accumulator_polynomials(eta); @@ -112,7 +112,7 @@ template void UltraProver_::execute_sorted_list_a template void UltraProver_::execute_log_derivative_inverse_round() { // Compute and store challenges beta and gamma - auto [beta, gamma] = challenges_to_field_elements(transcript->get_challenges("beta", "gamma")); + auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); relation_parameters.beta = beta; relation_parameters.gamma = gamma; @@ -151,12 +151,12 @@ template void UltraProver_::execute_relation_chec auto sumcheck = Sumcheck(circuit_size, transcript); RelationSeparator alphas; for (size_t idx = 0; idx < alphas.size(); idx++) { - alphas[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + alphas[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } instance->alphas = alphas; std::vector gate_challenges(numeric::get_msb(circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } instance->gate_challenges = gate_challenges; sumcheck_output = sumcheck.prove(instance); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 8e211390dd7..e212a38abfa 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -27,13 +27,13 @@ template class UltraProver_ { const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); - BBERG_PROFILE void execute_preamble_round(); - BBERG_PROFILE void execute_wire_commitments_round(); - BBERG_PROFILE void execute_sorted_list_accumulator_round(); - BBERG_PROFILE void execute_log_derivative_inverse_round(); - BBERG_PROFILE void execute_grand_product_computation_round(); - BBERG_PROFILE void execute_relation_check_rounds(); - BBERG_PROFILE void execute_zeromorph_rounds(); + BB_PROFILE void execute_preamble_round(); + BB_PROFILE void execute_wire_commitments_round(); + BB_PROFILE void execute_sorted_list_accumulator_round(); + BB_PROFILE void execute_log_derivative_inverse_round(); + BB_PROFILE void execute_grand_product_computation_round(); + BB_PROFILE void execute_relation_check_rounds(); + BB_PROFILE void execute_zeromorph_rounds(); HonkProof& export_proof(); HonkProof& construct_proof(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index 609b455e22f..1e5409c1e28 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -131,7 +131,7 @@ TEST_F(UltraTranscriptTests, ProverManifestConsistency) // Automatically generate a transcript manifest by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); @@ -158,12 +158,13 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) // Automatically generate a transcript manifest in the prover by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -187,7 +188,7 @@ TEST_F(UltraTranscriptTests, ChallengeGenerationTest) // initialized with random value sent to verifier auto transcript = Flavor::Transcript::prover_init_empty(); // test a bunch of challenges - auto challenges = transcript->get_challenges("a", "b", "c", "d", "e", "f"); + auto challenges = transcript->template get_challenges("a", "b", "c", "d", "e", "f"); // check they are not 0 for (size_t i = 0; i < challenges.size(); ++i) { ASSERT_NE(challenges[i], 0) << "Challenge " << i << " is 0"; @@ -195,7 +196,7 @@ TEST_F(UltraTranscriptTests, ChallengeGenerationTest) constexpr uint32_t random_val{ 17 }; // arbitrary transcript->send_to_verifier("random val", random_val); // test more challenges - auto [a, b, c] = challenges_to_field_elements(transcript->get_challenges("a", "b", "c")); + auto [a, b, c] = transcript->template get_challenges("a", "b", "c"); ASSERT_NE(a, 0) << "Challenge a is 0"; ASSERT_NE(b, 0) << "Challenge b is 0"; ASSERT_NE(c, 0) << "Challenge c is 0"; @@ -209,10 +210,11 @@ TEST_F(UltraTranscriptTests, StructureTest) // Automatically generate a transcript manifest by constructing a proof auto composer = UltraComposer(); - auto instance = composer.create_instance(builder); + auto instance = composer.create_prover_instance(builder); + auto verification_key = composer.compute_verification_key(instance); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance); + auto verifier = composer.create_verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 4ab7b6addf3..084e711ee71 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -97,7 +97,7 @@ template bool UltraVerifier_::verify_proof(const HonkP } // Get challenge for sorted list batching and wire four memory records - FF eta = transcript->get_challenge("eta"); + FF eta = transcript->template get_challenge("eta"); relation_parameters.eta = eta; // Get commitments to sorted list accumulator and fourth wire @@ -105,7 +105,7 @@ template bool UltraVerifier_::verify_proof(const HonkP commitments.w_4 = transcript->template receive_from_prover(commitment_labels.w_4); // Get permutation challenges - auto [beta, gamma] = challenges_to_field_elements(transcript->get_challenges("beta", "gamma")); + auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial if constexpr (IsGoblinFlavor) { @@ -131,12 +131,12 @@ template bool UltraVerifier_::verify_proof(const HonkP auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); RelationSeparator alphas; for (size_t idx = 0; idx < alphas.size(); idx++) { - alphas[idx] = transcript->get_challenge("Sumcheck:alpha_" + std::to_string(idx)); + alphas[idx] = transcript->template get_challenge("Sumcheck:alpha_" + std::to_string(idx)); } auto gate_challenges = std::vector(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alphas, gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_alu_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_alu_trace.cpp index 7da44d916bd..1425fb6bf78 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_alu_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_alu_trace.cpp @@ -47,11 +47,11 @@ std::vector AvmMiniAluTraceBuilder::final */ FF AvmMiniAluTraceBuilder::add(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t const clk) { - FF c{}; + FF c = 0; bool carry = false; - uint8_t alu_u8_r0{}; - uint8_t alu_u8_r1{}; - std::array alu_u16_reg{}; + uint8_t alu_u8_r0 = 0; + uint8_t alu_u8_r1 = 0; + std::array alu_u16_reg{}; // Must be zero-initialized (FF tag case) uint128_t a_u128{ a }; uint128_t b_u128{ b }; @@ -136,11 +136,11 @@ FF AvmMiniAluTraceBuilder::add(FF const& a, FF const& b, AvmMemoryTag in_tag, ui */ FF AvmMiniAluTraceBuilder::sub(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t const clk) { - FF c{}; + FF c = 0; bool carry = false; - uint8_t alu_u8_r0{}; - uint8_t alu_u8_r1{}; - std::array alu_u16_reg{}; + uint8_t alu_u8_r0 = 0; + uint8_t alu_u8_r1 = 0; + std::array alu_u16_reg{}; // Must be zero-initialized (FF tag case) uint128_t a_u128{ a }; uint128_t b_u128{ b }; uint128_t c_u128 = a_u128 - b_u128; @@ -220,12 +220,12 @@ FF AvmMiniAluTraceBuilder::sub(FF const& a, FF const& b, AvmMemoryTag in_tag, ui */ FF AvmMiniAluTraceBuilder::mul(FF const& a, FF const& b, AvmMemoryTag in_tag, uint32_t const clk) { - FF c{}; + FF c = 0; bool carry = false; - uint8_t alu_u8_r0{}; - uint8_t alu_u8_r1{}; + uint8_t alu_u8_r0 = 0; + uint8_t alu_u8_r1 = 0; - std::array alu_u16_reg{}; + std::array alu_u16_reg{}; // Must be zero-initialized (FF tag case) uint128_t a_u128{ a }; uint128_t b_u128{ b }; @@ -258,8 +258,8 @@ FF AvmMiniAluTraceBuilder::mul(FF const& a, FF const& b, AvmMemoryTag in_tag, ui uint128_t c_u128 = a_u128 * b_u128; // Decompose a_u128 and b_u128 over 8 16-bit registers. - std::array alu_u16_reg_a{}; - std::array alu_u16_reg_b{}; + std::array alu_u16_reg_a; // Will be initialized in for loop below. + std::array alu_u16_reg_b; // Will be initialized in for loop below. uint128_t a_trunc_128 = a_u128; uint128_t b_trunc_128 = b_u128; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp index fdbf49ebe57..1a8508377e6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_common.hpp @@ -4,12 +4,12 @@ #include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" #include +namespace avm_trace { + using Flavor = bb::AvmMiniFlavor; using FF = Flavor::FF; using Row = bb::AvmMiniFullRow; -namespace avm_trace { - // Number of rows static const size_t AVM_TRACE_SIZE = 256; enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2 }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.cpp new file mode 100644 index 00000000000..dace5225ecf --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.cpp @@ -0,0 +1,176 @@ +#include "AvmMini_deserialization.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_instructions.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" +#include +#include +#include +#include +#include +#include + +namespace avm_trace { + +namespace { + +const std::vector three_operand_format = { + OperandType::TAG, + OperandType::UINT32, + OperandType::UINT32, + OperandType::UINT32, +}; + +// Contrary to TS, the format does not contain the opcode byte which prefixes any instruction. +// The format for OpCode::SET has to be handled separately as it is variable based on the tag. +const std::unordered_map> OPCODE_WIRE_FORMAT = { + // Compute + // Compute - Arithmetic + { OpCode::ADD, three_operand_format }, + { OpCode::SUB, three_operand_format }, + { OpCode::MUL, three_operand_format }, + { OpCode::DIV, three_operand_format }, + // Execution Environment - Calldata + { OpCode::CALLDATACOPY, { OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, + // Machine State - Internal Control Flow + { OpCode::JUMP, { OperandType::UINT32 } }, + { OpCode::INTERNALCALL, { OperandType::UINT32 } }, + { OpCode::INTERNALRETURN, {} }, + // Machine State - Memory + // OpCode::SET is handled differently + // Control Flow - Contract Calls + { OpCode::RETURN, { OperandType::UINT32, OperandType::UINT32 } }, +}; + +const std::unordered_map OPERAND_TYPE_SIZE = { + { OperandType::TAG, 1 }, { OperandType::UINT8, 1 }, { OperandType::UINT16, 2 }, + { OperandType::UINT32, 4 }, { OperandType::UINT64, 8 }, { OperandType::UINT128, 16 }, +}; + +} // Anonymous namespace + +/** + * @brief Parsing of the supplied bytecode into a vector of instructions. It essentially + * checks that each opcode value is in the defined range and extracts the operands + * for each opcode based on the specification from OPCODE_WIRE_FORMAT. + * + * @param bytecode The bytecode to be parsed as a vector of bytes/uint8_t + * @throws runtime_error exception when the bytecode is invalid. + * @return Vector of instructions + */ +std::vector Deserialization::parse(std::vector const& bytecode) +{ + std::vector instructions; + size_t pos = 0; + const auto length = bytecode.size(); + + while (pos < length) { + const uint8_t opcode_byte = bytecode.at(pos); + + if (!Bytecode::is_valid(opcode_byte)) { + throw_or_abort("Invalid opcode byte: " + std::to_string(opcode_byte) + + " at position: " + std::to_string(pos)); + } + pos++; + + auto const opcode = static_cast(opcode_byte); + std::vector inst_format; + + if (opcode == OpCode::SET) { + if (pos == length) { + throw_or_abort("Operand for SET opcode is missing at position " + std::to_string(pos)); + } + + std::set const valid_tags = { static_cast(AvmMemoryTag::U8), + static_cast(AvmMemoryTag::U16), + static_cast(AvmMemoryTag::U32), + static_cast(AvmMemoryTag::U64), + static_cast(AvmMemoryTag::U128) }; + uint8_t set_tag_u8 = bytecode.at(pos); + + if (!valid_tags.contains(set_tag_u8)) { + throw_or_abort("Instruction tag for SET opcode is invalid at position " + std::to_string(pos) + + " value: " + std::to_string(set_tag_u8)); + } + + auto in_tag = static_cast(set_tag_u8); + switch (in_tag) { + case AvmMemoryTag::U8: + inst_format = { OperandType::TAG, OperandType::UINT8, OperandType::UINT32 }; + break; + case AvmMemoryTag::U16: + inst_format = { OperandType::TAG, OperandType::UINT16, OperandType::UINT32 }; + break; + case AvmMemoryTag::U32: + inst_format = { OperandType::TAG, OperandType::UINT32, OperandType::UINT32 }; + break; + case AvmMemoryTag::U64: + inst_format = { OperandType::TAG, OperandType::UINT64, OperandType::UINT32 }; + break; + case AvmMemoryTag::U128: + inst_format = { OperandType::TAG, OperandType::UINT128, OperandType::UINT32 }; + break; + default: // This branch is guarded above. + std::cerr << "This code branch must have been guarded by the tag validation. \n"; + assert(false); + } + } else { + inst_format = OPCODE_WIRE_FORMAT.at(opcode); + } + + std::vector operands; + + for (OperandType const& opType : inst_format) { + // No underflow as while condition guarantees pos <= length (after pos++) + if (length - pos < OPERAND_TYPE_SIZE.at(opType)) { + throw_or_abort("Operand is missing at position " + std::to_string(pos)); + } + + switch (opType) { + case OperandType::TAG: { + uint8_t tag_u8 = bytecode.at(pos); + if (tag_u8 == static_cast(AvmMemoryTag::U0) || tag_u8 > MAX_MEM_TAG) { + throw_or_abort("Instruction tag is invalid at position " + std::to_string(pos) + + " value: " + std::to_string(tag_u8)); + } + operands.emplace_back(static_cast(tag_u8)); + break; + } + case OperandType::UINT8: + operands.emplace_back(bytecode.at(pos)); + break; + case OperandType::UINT16: { + uint16_t operand_u16 = 0; + uint8_t const* pos_ptr = &bytecode.at(pos); + serialize::read(pos_ptr, operand_u16); + operands.emplace_back(operand_u16); + break; + } + case OperandType::UINT32: { + uint32_t operand_u32 = 0; + uint8_t const* pos_ptr = &bytecode.at(pos); + serialize::read(pos_ptr, operand_u32); + operands.emplace_back(operand_u32); + break; + } + case OperandType::UINT64: { + uint64_t operand_u64 = 0; + uint8_t const* pos_ptr = &bytecode.at(pos); + serialize::read(pos_ptr, operand_u64); + operands.emplace_back(operand_u64); + break; + } + case OperandType::UINT128: { + uint128_t operand_u128 = 0; + uint8_t const* pos_ptr = &bytecode.at(pos); + serialize::read(pos_ptr, operand_u128); + operands.emplace_back(operand_u128); + break; + } + } + pos += OPERAND_TYPE_SIZE.at(opType); + } + instructions.emplace_back(opcode, operands); + } + return instructions; +}; +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.hpp new file mode 100644 index 00000000000..91a52eaf41b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_deserialization.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "barretenberg/numeric/uint128/uint128.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_instructions.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" +#include +#include +#include +#include +#include + +namespace avm_trace { + +// Possible types for an instruction's operand in its wire format. (Keep in sync with TS code. +// See avm/serialization/instruction_serialization.ts). +// Note that the TAG enum value is not supported in TS and is parsed as UINT8. +enum class OperandType : uint8_t { TAG, UINT8, UINT16, UINT32, UINT64, UINT128 }; + +class Deserialization { + public: + Deserialization() = default; + + static std::vector parse(std::vector const& bytecode); +}; + +} // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp index 9a5f8f5a396..0aae8948100 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.cpp @@ -2,6 +2,7 @@ #include "barretenberg/common/serialize.hpp" #include "barretenberg/proof_system/circuit_builder/generated/AvmMini_circuit_builder.hpp" #include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_deserialization.hpp" #include "barretenberg/vm/avm_trace/AvmMini_instructions.hpp" #include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" #include "barretenberg/vm/avm_trace/AvmMini_trace.hpp" @@ -9,6 +10,7 @@ #include #include #include +#include #include using namespace bb; @@ -26,7 +28,7 @@ namespace avm_trace { */ HonkProof Execution::run_and_prove(std::vector const& bytecode, std::vector const& calldata) { - auto instructions = parse(bytecode); + auto instructions = Deserialization::parse(bytecode); auto trace = gen_trace(instructions, calldata); auto circuit_builder = bb::AvmMiniCircuitBuilder(); circuit_builder.set_trace(std::move(trace)); @@ -36,122 +38,6 @@ HonkProof Execution::run_and_prove(std::vector const& bytecode, std::ve return prover.construct_proof(); } -/** - * @brief Parsing of the supplied bytecode into a vector of instructions. It essentially - * checks that each opcode value is in the defined range and extracts the operands - * for each opcode. - * - * @param bytecode The bytecode to be parsed as a vector of bytes/uint8_t - * @throws runtime_error exception when the bytecode is invalid. - * @return Vector of instructions - */ -std::vector Execution::parse(std::vector const& bytecode) -{ - std::vector instructions; - size_t pos = 0; - const auto length = bytecode.size(); - - while (pos < length) { - const uint8_t opcode_byte = bytecode.at(pos); - pos += AVM_OPCODE_BYTE_LENGTH; - - if (!Bytecode::is_valid(opcode_byte)) { - throw std::runtime_error("Invalid opcode byte: " + std::to_string(opcode_byte)); - } - - const auto opcode = static_cast(opcode_byte); - auto in_tag_u8 = static_cast(AvmMemoryTag::U0); - - if (Bytecode::has_in_tag(opcode)) { - if (pos + AVM_IN_TAG_BYTE_LENGTH > length) { - throw std::runtime_error("Instruction tag missing at position " + std::to_string(pos)); - } - in_tag_u8 = bytecode.at(pos); - if (in_tag_u8 == static_cast(AvmMemoryTag::U0) || in_tag_u8 > MAX_MEM_TAG) { - throw std::runtime_error("Instruction tag is invalid at position " + std::to_string(pos) + - " value: " + std::to_string(in_tag_u8)); - } - pos += AVM_IN_TAG_BYTE_LENGTH; - } - - auto const in_tag = static_cast(in_tag_u8); - std::vector operands{}; - size_t num_of_operands{}; - size_t operands_size{}; - - // SET opcode particularity about the number of operands depending on the - // instruction tag. Namely, a constant of type instruction tag and not a - // memory address is passed in the operands. - // The bytecode of the operands is of the form CONSTANT || dst_offset - // CONSTANT is of size k bits for type Uk, k=8,16,32,64,128 - // dst_offset is of size 32 bits - // CONSTANT has to be decomposed into 32-bit chunks - if (opcode == OpCode::SET) { - switch (in_tag) { - case AvmMemoryTag::U8: - num_of_operands = 2; - operands_size = 5; - break; - case AvmMemoryTag::U16: - num_of_operands = 2; - operands_size = 6; - break; - case AvmMemoryTag::U32: - num_of_operands = 2; - operands_size = 8; - break; - case AvmMemoryTag::U64: - num_of_operands = 3; - operands_size = 12; - break; - case AvmMemoryTag::U128: - num_of_operands = 5; - operands_size = 20; - break; - default: - throw std::runtime_error("Instruction tag for SET opcode is invalid at position " + - std::to_string(pos) + " value: " + std::to_string(in_tag_u8)); - break; - } - } else { - num_of_operands = Bytecode::OPERANDS_NUM.at(opcode); - operands_size = AVM_OPERAND_BYTE_LENGTH * num_of_operands; - } - - if (pos + operands_size > length) { - throw std::runtime_error("Operand is missing at position " + std::to_string(pos)); - } - - // We handle operands which are encoded with less than 4 bytes. - // This occurs for opcode SET and tag U8 and U16. - if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U8) { - operands.push_back(static_cast(bytecode.at(pos))); - pos++; - num_of_operands--; - } else if (opcode == OpCode::SET && in_tag == AvmMemoryTag::U16) { - uint8_t const* ptr = &bytecode.at(pos); - uint16_t operand{}; - serialize::read(ptr, operand); - operands.push_back(static_cast(operand)); - pos += 2; - num_of_operands--; - } - - // Operands of size of 32 bits. - for (size_t i = 0; i < num_of_operands; i++) { - uint8_t const* ptr = &bytecode.at(pos); - uint32_t operand{}; - serialize::read(ptr, operand); - operands.push_back(operand); - pos += AVM_OPERAND_BYTE_LENGTH; - } - - instructions.emplace_back(opcode, operands, static_cast(in_tag)); - } - - return instructions; -} - /** * @brief Generate the execution trace pertaining to the supplied instructions. * @@ -161,9 +47,9 @@ std::vector Execution::parse(std::vector const& bytecode) */ std::vector Execution::gen_trace(std::vector const& instructions, std::vector const& calldata) { - AvmMiniTraceBuilder trace_builder{}; + AvmMiniTraceBuilder trace_builder; - // copied version of pc maintained in trace builder. The value of pc is evolving based + // Copied version of pc maintained in trace builder. The value of pc is evolving based // on opcode logic and therefore is not maintained here. However, the next opcode in the execution // is determined by this value which require read access to the code below. uint32_t pc = 0; @@ -173,62 +59,82 @@ std::vector Execution::gen_trace(std::vector const& instructio auto inst = instructions.at(pc); switch (inst.op_code) { + // Compute + // Compute - Arithmetic case OpCode::ADD: - trace_builder.add(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + trace_builder.add(std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(0))); break; case OpCode::SUB: - trace_builder.sub(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + trace_builder.sub(std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(0))); break; case OpCode::MUL: - trace_builder.mul(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + trace_builder.mul(std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(0))); break; case OpCode::DIV: - trace_builder.div(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), inst.in_tag); + trace_builder.div(std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), + std::get(inst.operands.at(0))); break; + // Execution Environment - Calldata case OpCode::CALLDATACOPY: - trace_builder.calldata_copy(inst.operands.at(0), inst.operands.at(1), inst.operands.at(2), calldata); + trace_builder.calldata_copy(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2)), + calldata); break; + // Machine State - Internal Control Flow case OpCode::JUMP: - trace_builder.jump(inst.operands.at(0)); + trace_builder.jump(std::get(inst.operands.at(0))); break; case OpCode::INTERNALCALL: - trace_builder.internal_call(inst.operands.at(0)); + trace_builder.internal_call(std::get(inst.operands.at(0))); break; case OpCode::INTERNALRETURN: trace_builder.internal_return(); break; + // Machine State - Memory case OpCode::SET: { - uint32_t dst_offset{}; - uint128_t val{}; - switch (inst.in_tag) { + uint32_t dst_offset = 0; + uint128_t val = 0; + AvmMemoryTag in_tag = std::get(inst.operands.at(0)); + dst_offset = std::get(inst.operands.at(2)); + + switch (in_tag) { case AvmMemoryTag::U8: + val = std::get(inst.operands.at(1)); + break; case AvmMemoryTag::U16: + val = std::get(inst.operands.at(1)); + break; case AvmMemoryTag::U32: - // U8, U16, U32 value represented in a single uint32_t operand - val = inst.operands.at(0); - dst_offset = inst.operands.at(1); + val = std::get(inst.operands.at(1)); break; - case AvmMemoryTag::U64: // value represented as 2 uint32_t operands - val = inst.operands.at(0); - val <<= 32; - val += inst.operands.at(1); - dst_offset = inst.operands.at(2); + case AvmMemoryTag::U64: + val = std::get(inst.operands.at(1)); break; - case AvmMemoryTag::U128: // value represented as 4 uint32_t operands - for (size_t i = 0; i < 4; i++) { - val += inst.operands.at(i); - val <<= 32; - } - dst_offset = inst.operands.at(4); + case AvmMemoryTag::U128: + val = std::get(inst.operands.at(1)); break; default: break; } - trace_builder.set(val, dst_offset, inst.in_tag); + + trace_builder.set(val, dst_offset, in_tag); break; } + // Control Flow - Contract Calls case OpCode::RETURN: - trace_builder.return_op(inst.operands.at(0), inst.operands.at(1)); + trace_builder.return_op(std::get(inst.operands.at(0)), std::get(inst.operands.at(1))); break; default: break; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp index ae041f65bb0..40c75d186e2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_execution.hpp @@ -14,15 +14,9 @@ class Execution { public: Execution() = default; - static size_t const AVM_OPERAND_BYTE_LENGTH = 4; // Keep in sync with TS code - static_assert(sizeof(uint32_t) / sizeof(uint8_t) == AVM_OPERAND_BYTE_LENGTH); - - static size_t const AVM_OPCODE_BYTE_LENGTH = 1; // Keep in sync with TS code - static size_t const AVM_IN_TAG_BYTE_LENGTH = 1; // Keep in sync with TS code - - static std::vector parse(std::vector const& bytecode); - static std::vector gen_trace(std::vector const& instructions, std::vector const& calldata); - static bb::HonkProof run_and_prove(std::vector const& bytecode, std::vector const& calldata); + static std::vector gen_trace(std::vector const& instructions, + std::vector const& calldata = {}); + static bb::HonkProof run_and_prove(std::vector const& bytecode, std::vector const& calldata = {}); }; } // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp index 0cc18e56087..497961685ea 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_instructions.hpp @@ -1,5 +1,6 @@ #pragma once +#include "barretenberg/numeric/uint128/uint128.hpp" #include "barretenberg/vm/avm_trace/AvmMini_common.hpp" #include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" #include @@ -7,17 +8,17 @@ namespace avm_trace { +using Operand = std::variant; + class Instruction { public: OpCode op_code; - std::vector operands; - AvmMemoryTag in_tag; + std::vector operands; Instruction() = delete; - explicit Instruction(OpCode op_code, std::vector operands, AvmMemoryTag in_tag) + explicit Instruction(OpCode op_code, std::vector operands) : op_code(op_code) - , operands(std::move(operands)) - , in_tag(in_tag){}; + , operands(std::move(operands)){}; }; } // namespace avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp index c945f6158c6..bdb03bde7b0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_opcode.hpp @@ -1,10 +1,10 @@ #pragma once +#include #include #include namespace avm_trace { -using std::size_t; /** * All AVM opcodes (Keep in sync with TS counterpart code opcodes.ts) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp index 88aac4a09e6..85f9906533f 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/AvmMini_trace.cpp @@ -377,7 +377,7 @@ std::vector AvmMiniTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret { if (ret_size == 0) { halt(); - return std::vector{}; + return {}; } // We parallelize loading memory operations in chunk of 3, i.e., 1 per intermediate register. @@ -604,7 +604,7 @@ std::vector AvmMiniTraceBuilder::finalize() // Fill the rest with zeros. size_t zero_rows_num = AVM_TRACE_SIZE - main_trace_size - 1; while (zero_rows_num-- > 0) { - main_trace.push_back(Row{}); + main_trace.push_back({}); } main_trace.at(main_trace_size - 1).avmMini_last = FF(1); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp index d79339a530b..9e79beae75f 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_prover.cpp @@ -73,12 +73,11 @@ void AvmMiniProver::execute_relation_check_rounds() using Sumcheck = SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp index 8d093e0fee3..e73881458ce 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/AvmMini_verifier.cpp @@ -164,12 +164,10 @@ bool AvmMiniVerifier::verify_proof(const HonkProof& proof) // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); - - FF alpha = transcript->get_challenge("Sumcheck:alpha"); - + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); auto gate_challenges = std::vector(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp index dd76091689d..525726c645a 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_prover.cpp @@ -70,10 +70,10 @@ void ToyProver::execute_relation_check_rounds() { using Sumcheck = SumcheckProver; auto sumcheck = Sumcheck(key->circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); std::vector gate_challenges(numeric::get_msb(key->circuit_size)); for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); } diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp index b430c530234..327822cfdd9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/Toy_verifier.cpp @@ -82,10 +82,10 @@ bool ToyVerifier::verify_proof(const HonkProof& proof) // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); - FF alpha = transcript->get_challenge("Sumcheck:alpha"); + FF alpha = transcript->template get_challenge("Sumcheck:alpha"); auto gate_challenges = std::vector(log_circuit_size); for (size_t idx = 0; idx < log_circuit_size; idx++) { - gate_challenges[idx] = transcript->get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); + gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); } auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = sumcheck.verify(relation_parameters, alpha, gate_challenges); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp index ce2fcf868b1..5ff248a6c2d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/AvmMini_execution.test.cpp @@ -2,16 +2,26 @@ #include "AvmMini_common.test.hpp" #include "barretenberg/common/utils.hpp" #include "barretenberg/vm/avm_trace/AvmMini_common.hpp" +#include "barretenberg/vm/avm_trace/AvmMini_deserialization.hpp" #include "barretenberg/vm/avm_trace/AvmMini_helper.hpp" #include "barretenberg/vm/avm_trace/AvmMini_opcode.hpp" #include "barretenberg/vm/tests/helpers.test.hpp" +#include "gmock/gmock.h" #include #include #include #include +namespace tests_avm { + using namespace bb; +using namespace avm_trace; +using namespace testing; + +using bb::utils::hex_to_bytes; + namespace { + void gen_proof_and_validate(std::vector const& bytecode, std::vector&& trace, std::vector const& calldata) @@ -29,10 +39,6 @@ void gen_proof_and_validate(std::vector const& bytecode, } } // namespace -namespace tests_avm { -using namespace avm_trace; -using bb::utils::hex_to_bytes; - class AvmMiniExecutionTests : public ::testing::Test { public: AvmMiniTraceBuilder trace_builder; @@ -60,28 +66,27 @@ TEST_F(AvmMiniExecutionTests, basicAddReturn) "00000000"; // ret size 0 auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); // 2 instructions - EXPECT_EQ(instructions.size(), 2); + ASSERT_THAT(instructions, SizeIs(2)); // ADD - EXPECT_EQ(instructions.at(0).op_code, OpCode::ADD); - EXPECT_EQ(instructions.at(0).operands.size(), 3); - EXPECT_EQ(instructions.at(0).operands.at(0), 7); - EXPECT_EQ(instructions.at(0).operands.at(1), 9); - EXPECT_EQ(instructions.at(0).operands.at(2), 1); - EXPECT_EQ(instructions.at(0).in_tag, AvmMemoryTag::U8); + EXPECT_THAT(instructions.at(0), + AllOf(Field(&Instruction::op_code, OpCode::ADD), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U8), + VariantWith(7), + VariantWith(9), + VariantWith(1))))); // RETURN - EXPECT_EQ(instructions.at(1).op_code, OpCode::RETURN); - EXPECT_EQ(instructions.at(1).operands.size(), 2); - EXPECT_EQ(instructions.at(1).operands.at(0), 0); - EXPECT_EQ(instructions.at(1).operands.at(0), 0); + EXPECT_THAT(instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::RETURN), + Field(&Instruction::operands, ElementsAre(VariantWith(0), VariantWith(0))))); - auto trace = Execution::gen_trace(instructions, std::vector{}); - - gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); + auto trace = Execution::gen_trace(instructions); + gen_proof_and_validate(bytecode, std::move(trace), {}); } // Positive test for SET and SUB opcodes @@ -105,38 +110,42 @@ TEST_F(AvmMiniExecutionTests, setAndSubOpcodes) "00000000"; // ret size 0 auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); - EXPECT_EQ(instructions.size(), 4); + ASSERT_THAT(instructions, SizeIs(4)); // SET - EXPECT_EQ(instructions.at(0).op_code, OpCode::SET); - EXPECT_EQ(instructions.at(0).operands.size(), 2); - EXPECT_EQ(instructions.at(0).operands.at(0), 47123); - EXPECT_EQ(instructions.at(0).operands.at(1), 170); - EXPECT_EQ(instructions.at(0).in_tag, AvmMemoryTag::U16); + EXPECT_THAT(instructions.at(0), + AllOf(Field(&Instruction::op_code, OpCode::SET), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U16), + VariantWith(47123), + VariantWith(170))))); // SET - EXPECT_EQ(instructions.at(1).op_code, OpCode::SET); - EXPECT_EQ(instructions.at(1).operands.size(), 2); - EXPECT_EQ(instructions.at(1).operands.at(0), 37123); - EXPECT_EQ(instructions.at(1).operands.at(1), 51); - EXPECT_EQ(instructions.at(1).in_tag, AvmMemoryTag::U16); + EXPECT_THAT(instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::SET), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U16), + VariantWith(37123), + VariantWith(51))))); // SUB - EXPECT_EQ(instructions.at(2).op_code, OpCode::SUB); - EXPECT_EQ(instructions.at(2).operands.size(), 3); - EXPECT_EQ(instructions.at(2).operands.at(0), 170); - EXPECT_EQ(instructions.at(2).operands.at(1), 51); - EXPECT_EQ(instructions.at(2).in_tag, AvmMemoryTag::U16); + EXPECT_THAT(instructions.at(2), + AllOf(Field(&Instruction::op_code, OpCode::SUB), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U16), + VariantWith(170), + VariantWith(51), + VariantWith(1))))); - auto trace = Execution::gen_trace(instructions, std::vector{}); + auto trace = Execution::gen_trace(instructions); // Find the first row enabling the subtraction selector auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_sub == 1; }); EXPECT_EQ(row->avmMini_ic, 10000); // 47123 - 37123 = 10000 - gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); + gen_proof_and_validate(bytecode, std::move(trace), {}); } // Positive test for multiple MUL opcodes @@ -168,48 +177,48 @@ TEST_F(AvmMiniExecutionTests, powerWithMulOpcodes) "00000000" // ret offset 0 "00000000"; // ret size 0 - uint8_t num = 12; - while (num-- > 0) { + for (int i = 0; i < 12; i++) { bytecode_hex.append(mul_hex); } bytecode_hex.append(ret_hex); auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); - EXPECT_EQ(instructions.size(), 15); + ASSERT_THAT(instructions, SizeIs(15)); // MUL first pos - EXPECT_EQ(instructions.at(2).op_code, OpCode::MUL); - EXPECT_EQ(instructions.at(2).operands.size(), 3); - EXPECT_EQ(instructions.at(2).operands.at(0), 0); - EXPECT_EQ(instructions.at(2).operands.at(1), 1); - EXPECT_EQ(instructions.at(2).operands.at(2), 1); - EXPECT_EQ(instructions.at(2).in_tag, AvmMemoryTag::U64); + EXPECT_THAT(instructions.at(2), + AllOf(Field(&Instruction::op_code, OpCode::MUL), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U64), + VariantWith(0), + VariantWith(1), + VariantWith(1))))); // MUL last pos - EXPECT_EQ(instructions.at(13).op_code, OpCode::MUL); - EXPECT_EQ(instructions.at(13).operands.size(), 3); - EXPECT_EQ(instructions.at(13).operands.at(0), 0); - EXPECT_EQ(instructions.at(13).operands.at(1), 1); - EXPECT_EQ(instructions.at(13).operands.at(2), 1); - EXPECT_EQ(instructions.at(13).in_tag, AvmMemoryTag::U64); + EXPECT_THAT(instructions.at(13), + AllOf(Field(&Instruction::op_code, OpCode::MUL), + Field(&Instruction::operands, + ElementsAre(VariantWith(AvmMemoryTag::U64), + VariantWith(0), + VariantWith(1), + VariantWith(1))))); // RETURN - EXPECT_EQ(instructions.at(14).op_code, OpCode::RETURN); - EXPECT_EQ(instructions.at(14).operands.size(), 2); - EXPECT_EQ(instructions.at(14).operands.at(0), 0); - EXPECT_EQ(instructions.at(14).operands.at(0), 0); + EXPECT_THAT(instructions.at(14), + AllOf(Field(&Instruction::op_code, OpCode::RETURN), + Field(&Instruction::operands, ElementsAre(VariantWith(0), VariantWith(0))))); - auto trace = Execution::gen_trace(instructions, std::vector{}); + auto trace = Execution::gen_trace(instructions); // Find the first row enabling the multiplication selector and pc = 13 auto row = std::ranges::find_if( trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_mul == 1 && r.avmMini_pc == 13; }); EXPECT_EQ(row->avmMini_ic, 244140625); // 5^12 = 244140625 - gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); + gen_proof_and_validate(bytecode, std::move(trace), {}); } // Positive test about a single internal_call and internal_return @@ -245,21 +254,21 @@ TEST_F(AvmMiniExecutionTests, simpleInternalCall) ; auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); - EXPECT_EQ(instructions.size(), 6); + EXPECT_THAT(instructions, SizeIs(6)); // We test parsing step for INTERNALCALL and INTERNALRETURN. // INTERNALCALL - EXPECT_EQ(instructions.at(1).op_code, OpCode::INTERNALCALL); - EXPECT_EQ(instructions.at(1).operands.size(), 1); - EXPECT_EQ(instructions.at(1).operands.at(0), 4); + EXPECT_THAT(instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::INTERNALCALL), + Field(&Instruction::operands, ElementsAre(VariantWith(4))))); // INTERNALRETURN EXPECT_EQ(instructions.at(5).op_code, OpCode::INTERNALRETURN); - auto trace = Execution::gen_trace(instructions, std::vector{}); + auto trace = Execution::gen_trace(instructions); // Expected sequence of PCs during execution std::vector pc_sequence{ 0, 1, 4, 5, 2, 3 }; @@ -272,7 +281,7 @@ TEST_F(AvmMiniExecutionTests, simpleInternalCall) auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avmMini_sel_op_add == 1; }); EXPECT_EQ(row->avmMini_ic, 345567789); - gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); + gen_proof_and_validate(bytecode, std::move(trace), {}); } // Positive test with some nested internall calls @@ -322,9 +331,9 @@ TEST_F(AvmMiniExecutionTests, nestedInternalCalls) bytecode_f2 + bytecode_f1 + bytecode_g; auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); - EXPECT_EQ(instructions.size(), 12); + ASSERT_THAT(instructions, SizeIs(12)); // Expected sequence of opcodes std::vector const opcode_sequence{ OpCode::SET, OpCode::SET, @@ -338,7 +347,7 @@ TEST_F(AvmMiniExecutionTests, nestedInternalCalls) EXPECT_EQ(instructions.at(i).op_code, opcode_sequence.at(i)); } - auto trace = Execution::gen_trace(instructions, std::vector{}); + auto trace = Execution::gen_trace(instructions); // Expected sequence of PCs during execution std::vector pc_sequence{ 0, 1, 2, 8, 6, 7, 9, 10, 4, 5, 11, 3 }; @@ -352,7 +361,7 @@ TEST_F(AvmMiniExecutionTests, nestedInternalCalls) EXPECT_EQ(row->avmMini_ic, 187); EXPECT_EQ(row->avmMini_pc, 4); - gen_proof_and_validate(bytecode, std::move(trace), std::vector{}); + gen_proof_and_validate(bytecode, std::move(trace), {}); } // Positive test with JUMP and CALLDATACOPY @@ -385,23 +394,23 @@ TEST_F(AvmMiniExecutionTests, jumpAndCalldatacopy) ; auto bytecode = hex_to_bytes(bytecode_hex); - auto instructions = Execution::parse(bytecode); + auto instructions = Deserialization::parse(bytecode); - EXPECT_EQ(instructions.size(), 5); + ASSERT_THAT(instructions, SizeIs(5)); // We test parsing steps for CALLDATACOPY and JUMP. // CALLDATACOPY - EXPECT_EQ(instructions.at(0).op_code, OpCode::CALLDATACOPY); - EXPECT_EQ(instructions.at(0).operands.size(), 3); - EXPECT_EQ(instructions.at(0).operands.at(0), 0); - EXPECT_EQ(instructions.at(0).operands.at(1), 2); - EXPECT_EQ(instructions.at(0).operands.at(2), 10); + EXPECT_THAT( + instructions.at(0), + AllOf(Field(&Instruction::op_code, OpCode::CALLDATACOPY), + Field(&Instruction::operands, + ElementsAre(VariantWith(0), VariantWith(2), VariantWith(10))))); // JUMP - EXPECT_EQ(instructions.at(1).op_code, OpCode::JUMP); - EXPECT_EQ(instructions.at(1).operands.size(), 1); - EXPECT_EQ(instructions.at(1).operands.at(0), 3); + EXPECT_THAT(instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::JUMP), + Field(&Instruction::operands, ElementsAre(VariantWith(3))))); auto trace = Execution::gen_trace(instructions, std::vector{ 13, 156 }); @@ -437,7 +446,7 @@ TEST_F(AvmMiniExecutionTests, invalidOpcode) "00000000"; // ret size 0 auto bytecode = hex_to_bytes(bytecode_hex); - EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "opcode"); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Invalid opcode"); } // Negative test detecting an invalid memmory instruction tag. @@ -453,7 +462,7 @@ TEST_F(AvmMiniExecutionTests, invalidInstructionTag) "00000000"; // ret size 0 auto bytecode = hex_to_bytes(bytecode_hex); - EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag is invalid"); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Instruction tag is invalid"); } // Negative test detecting SET opcode with instruction memory tag set to FF. @@ -469,7 +478,21 @@ TEST_F(AvmMiniExecutionTests, ffInstructionTagSetOpcode) "00002344"; // auto bytecode = hex_to_bytes(bytecode_hex); - EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag for SET opcode is invalid"); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Instruction tag for SET opcode is invalid"); +} + +// Negative test detecting SET opcode without any operand. +TEST_F(AvmMiniExecutionTests, SetOpcodeNoOperand) +{ + std::string bytecode_hex = "00" // ADD + "05" // U128 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + "27"; // SET 39 = 0x27 + + auto bytecode = hex_to_bytes(bytecode_hex); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Operand for SET opcode is missing"); } // Negative test detecting an incomplete instruction: missing instruction tag @@ -483,7 +506,7 @@ TEST_F(AvmMiniExecutionTests, truncatedInstructionNoTag) "01"; // SUB auto bytecode = hex_to_bytes(bytecode_hex); - EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Instruction tag missing"); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Operand is missing"); } // Negative test detecting an incomplete instruction: instruction tag present but an operand is missing @@ -500,7 +523,7 @@ TEST_F(AvmMiniExecutionTests, truncatedInstructionNoOperand) "FFFFFFBB"; // addr b and missing address for c = a-b auto bytecode = hex_to_bytes(bytecode_hex); - EXPECT_THROW_WITH_MESSAGE(Execution::parse(bytecode), "Operand is missing"); + EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Operand is missing"); } } // namespace tests_avm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp index 430c1cce45b..d6071fe421e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.hpp @@ -11,6 +11,11 @@ EXPECT_TRUE(message.find(expectedMessage) != std::string::npos); \ } namespace tests_avm { + +using Flavor = bb::AvmMiniFlavor; +using FF = Flavor::FF; +using Row = bb::AvmMiniFullRow; + void validate_trace_proof(std::vector&& trace); void mutate_ic_in_trace(std::vector& trace, std::function&& selectRow, diff --git a/barretenberg/sol/src/ultra/BaseUltraVerifier.sol b/barretenberg/sol/src/ultra/BaseUltraVerifier.sol index e00052d6a8e..507e644e794 100644 --- a/barretenberg/sol/src/ultra/BaseUltraVerifier.sol +++ b/barretenberg/sol/src/ultra/BaseUltraVerifier.sol @@ -215,56 +215,49 @@ abstract contract BaseUltraVerifier { uint256 internal constant PAIRING_RHS_X_LOC = 0x3220; uint256 internal constant PAIRING_RHS_Y_LOC = 0x3240; - // ### SUCCESS FLAG MEMORY LOCATIONS - uint256 internal constant GRAND_PRODUCT_SUCCESS_FLAG = 0x3300; - uint256 internal constant ARITHMETIC_TERM_SUCCESS_FLAG = 0x3020; - uint256 internal constant BATCH_OPENING_SUCCESS_FLAG = 0x3340; - uint256 internal constant OPENING_COMMITMENT_SUCCESS_FLAG = 0x3360; - uint256 internal constant PAIRING_PREAMBLE_SUCCESS_FLAG = 0x3380; - uint256 internal constant PAIRING_SUCCESS_FLAG = 0x33a0; - uint256 internal constant RESULT_FLAG = 0x33c0; - // misc stuff - uint256 internal constant OMEGA_INVERSE_LOC = 0x3400; - uint256 internal constant C_ALPHA_SQR_LOC = 0x3420; - uint256 internal constant C_ALPHA_CUBE_LOC = 0x3440; - uint256 internal constant C_ALPHA_QUAD_LOC = 0x3460; - uint256 internal constant C_ALPHA_BASE_LOC = 0x3480; + uint256 internal constant OMEGA_INVERSE_LOC = 0x3300; + uint256 internal constant C_ALPHA_SQR_LOC = 0x3320; + uint256 internal constant C_ALPHA_CUBE_LOC = 0x3340; + uint256 internal constant C_ALPHA_QUAD_LOC = 0x3360; + uint256 internal constant C_ALPHA_BASE_LOC = 0x3380; // ### RECURSION VARIABLE MEMORY LOCATIONS - uint256 internal constant RECURSIVE_P1_X_LOC = 0x3500; - uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3520; - uint256 internal constant RECURSIVE_P2_X_LOC = 0x3540; - uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3560; - - uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3580; + uint256 internal constant RECURSIVE_P1_X_LOC = 0x3400; + uint256 internal constant RECURSIVE_P1_Y_LOC = 0x3420; + uint256 internal constant RECURSIVE_P2_X_LOC = 0x3440; + uint256 internal constant RECURSIVE_P2_Y_LOC = 0x3460; + uint256 internal constant PUBLIC_INPUTS_HASH_LOCATION = 0x3480; // sub-identity storage - uint256 internal constant PERMUTATION_IDENTITY = 0x3600; - uint256 internal constant PLOOKUP_IDENTITY = 0x3620; - uint256 internal constant ARITHMETIC_IDENTITY = 0x3640; - uint256 internal constant SORT_IDENTITY = 0x3660; - uint256 internal constant ELLIPTIC_IDENTITY = 0x3680; - uint256 internal constant AUX_IDENTITY = 0x36a0; - uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x36c0; - uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x36e0; - uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3700; - uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3720; - uint256 internal constant AUX_MEMORY_EVALUATION = 0x3740; - - uint256 internal constant QUOTIENT_EVAL_LOC = 0x3760; - uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3780; + uint256 internal constant PERMUTATION_IDENTITY = 0x3500; + uint256 internal constant PLOOKUP_IDENTITY = 0x3520; + uint256 internal constant ARITHMETIC_IDENTITY = 0x3540; + uint256 internal constant SORT_IDENTITY = 0x3560; + uint256 internal constant ELLIPTIC_IDENTITY = 0x3580; + uint256 internal constant AUX_IDENTITY = 0x35a0; + uint256 internal constant AUX_NON_NATIVE_FIELD_EVALUATION = 0x35c0; + uint256 internal constant AUX_LIMB_ACCUMULATOR_EVALUATION = 0x35e0; + uint256 internal constant AUX_RAM_CONSISTENCY_EVALUATION = 0x3600; + uint256 internal constant AUX_ROM_CONSISTENCY_EVALUATION = 0x3620; + uint256 internal constant AUX_MEMORY_EVALUATION = 0x3640; + + uint256 internal constant QUOTIENT_EVAL_LOC = 0x3660; + uint256 internal constant ZERO_POLY_INVERSE_LOC = 0x3680; // when hashing public inputs we use memory at NU_CHALLENGE_INPUT_LOC_A, as the hash input size is unknown at compile time - uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x37a0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x37c0; - uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x37e0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_A = 0x36a0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_B = 0x36c0; + uint256 internal constant NU_CHALLENGE_INPUT_LOC_C = 0x36e0; + bytes4 internal constant INVALID_VERIFICATION_KEY_SELECTOR = 0x7e5769bf; + bytes4 internal constant POINT_NOT_ON_CURVE_SELECTOR = 0xa3dad654; bytes4 internal constant PUBLIC_INPUT_INVALID_BN128_G1_POINT_SELECTOR = 0xeba9f4a6; bytes4 internal constant PUBLIC_INPUT_GE_P_SELECTOR = 0x374a972f; bytes4 internal constant MOD_EXP_FAILURE_SELECTOR = 0xf894a7bc; - bytes4 internal constant EC_SCALAR_MUL_FAILURE_SELECTOR = 0xf755f369; - bytes4 internal constant PROOF_FAILURE_SELECTOR = 0x0711fcec; + bytes4 internal constant PAIRING_PREAMBLE_FAILED_SELECTOR = 0x01882d81; + bytes4 internal constant OPENING_COMMITMENT_FAILED_SELECTOR = 0x4e719763; + bytes4 internal constant PAIRING_FAILED_SELECTOR = 0xd71fd263; uint256 internal constant ETA_INPUT_LENGTH = 0xc0; // W1, W2, W3 = 6 * 0x20 bytes @@ -289,17 +282,226 @@ abstract contract BaseUltraVerifier { // for Grumpkin, a = 0 and b = -17. We use b in a custom gate relation that evaluates elliptic curve arithmetic uint256 internal constant GRUMPKIN_CURVE_B_PARAMETER_NEGATED = 17; + error INVALID_VERIFICATION_KEY(); + error POINT_NOT_ON_CURVE(); error PUBLIC_INPUT_COUNT_INVALID(uint256 expected, uint256 actual); error PUBLIC_INPUT_INVALID_BN128_G1_POINT(); error PUBLIC_INPUT_GE_P(); error MOD_EXP_FAILURE(); - error EC_SCALAR_MUL_FAILURE(); - error PROOF_FAILURE(); + error PAIRING_PREAMBLE_FAILED(); + error OPENING_COMMITMENT_FAILED(); + error PAIRING_FAILED(); function getVerificationKeyHash() public pure virtual returns (bytes32); + /** + * @dev We assume that the verification key loaded by this function is constant as we only verify it on deployment + */ function loadVerificationKey(uint256 _vk, uint256 _omegaInverseLoc) internal pure virtual; + constructor() { + loadVerificationKey(N_LOC, OMEGA_INVERSE_LOC); + + // We verify that all of the EC points in the verification key lie on the bn128 curve. + assembly { + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // EC group order + + let success := 1 + + // VALIDATE Q1 + { + let x := mload(Q1_X_LOC) + let y := mload(Q1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q2 + { + let x := mload(Q2_X_LOC) + let y := mload(Q2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q3 + { + let x := mload(Q3_X_LOC) + let y := mload(Q3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE Q4 + { + let x := mload(Q4_X_LOC) + let y := mload(Q4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + mstore(0x00, x) + mstore(0x20, y) + } + // VALIDATE QM + { + let x := mload(QM_X_LOC) + let y := mload(QM_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QC + { + let x := mload(QC_X_LOC) + let y := mload(QC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QARITH + { + let x := mload(QARITH_X_LOC) + let y := mload(QARITH_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QSORT + { + let x := mload(QSORT_X_LOC) + let y := mload(QSORT_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QELLIPTIC + { + let x := mload(QELLIPTIC_X_LOC) + let y := mload(QELLIPTIC_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE QAUX + { + let x := mload(QAUX_X_LOC) + let y := mload(QAUX_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA1 + { + let x := mload(SIGMA1_X_LOC) + let y := mload(SIGMA1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA2 + { + let x := mload(SIGMA2_X_LOC) + let y := mload(SIGMA2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA3 + { + let x := mload(SIGMA3_X_LOC) + let y := mload(SIGMA3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE SIGMA4 + { + let x := mload(SIGMA4_X_LOC) + let y := mload(SIGMA4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE1 + { + let x := mload(TABLE1_X_LOC) + let y := mload(TABLE1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE2 + { + let x := mload(TABLE2_X_LOC) + let y := mload(TABLE2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE3 + { + let x := mload(TABLE3_X_LOC) + let y := mload(TABLE3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE4 + { + let x := mload(TABLE4_X_LOC) + let y := mload(TABLE4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE TABLE_TYPE + { + let x := mload(TABLE_TYPE_X_LOC) + let y := mload(TABLE_TYPE_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID1 + { + let x := mload(ID1_X_LOC) + let y := mload(ID1_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID2 + { + let x := mload(ID2_X_LOC) + let y := mload(ID2_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID3 + { + let x := mload(ID3_X_LOC) + let y := mload(ID3_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + // VALIDATE ID4 + { + let x := mload(ID4_X_LOC) + let y := mload(ID4_Y_LOC) + let xx := mulmod(x, x, q) + // validate on curve + success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + } + + if iszero(success) { + mstore(0x0, INVALID_VERIFICATION_KEY_SELECTOR) + revert(0x00, 0x04) + } + } + } + /** * @notice Verify a Ultra Plonk proof * @param _proof - The serialized proof @@ -1695,7 +1897,10 @@ abstract contract BaseUltraVerifier { let y := mload(T1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(ACCUMULATOR_X_LOC, x) mstore(add(ACCUMULATOR_X_LOC, 0x20), y) } @@ -1705,13 +1910,16 @@ abstract contract BaseUltraVerifier { let y := mload(T2_Y_LOC) // 0x1420 let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } mstore(0x40, mload(ZETA_POW_N_LOC)) // accumulator_2 = [T2].zeta^n - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40) // accumulator = [T1] + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) @@ -1721,7 +1929,10 @@ abstract contract BaseUltraVerifier { let y := mload(T3_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1737,7 +1948,10 @@ abstract contract BaseUltraVerifier { let y := mload(T4_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1753,7 +1967,10 @@ abstract contract BaseUltraVerifier { let y := mload(W1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1769,7 +1986,10 @@ abstract contract BaseUltraVerifier { let y := mload(W2_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1785,7 +2005,10 @@ abstract contract BaseUltraVerifier { let y := mload(W3_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1801,7 +2024,10 @@ abstract contract BaseUltraVerifier { let y := mload(W4_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1817,7 +2043,10 @@ abstract contract BaseUltraVerifier { let y := mload(S_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1833,7 +2062,10 @@ abstract contract BaseUltraVerifier { let y := mload(Z_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1849,7 +2081,10 @@ abstract contract BaseUltraVerifier { let y := mload(Z_LOOKUP_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -1864,8 +2099,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q1_X_LOC) let y := mload(Q1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1880,8 +2114,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q2_X_LOC) let y := mload(Q2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1896,8 +2129,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q3_X_LOC) let y := mload(Q3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1912,8 +2144,7 @@ abstract contract BaseUltraVerifier { let x := mload(Q4_X_LOC) let y := mload(Q4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1928,8 +2159,7 @@ abstract contract BaseUltraVerifier { let x := mload(QM_X_LOC) let y := mload(QM_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1944,8 +2174,7 @@ abstract contract BaseUltraVerifier { let x := mload(QC_X_LOC) let y := mload(QC_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1960,8 +2189,7 @@ abstract contract BaseUltraVerifier { let x := mload(QARITH_X_LOC) let y := mload(QARITH_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1976,8 +2204,7 @@ abstract contract BaseUltraVerifier { let x := mload(QSORT_X_LOC) let y := mload(QSORT_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -1992,8 +2219,7 @@ abstract contract BaseUltraVerifier { let x := mload(QELLIPTIC_X_LOC) let y := mload(QELLIPTIC_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2008,8 +2234,7 @@ abstract contract BaseUltraVerifier { let x := mload(QAUX_X_LOC) let y := mload(QAUX_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2024,8 +2249,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA1_X_LOC) let y := mload(SIGMA1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2040,8 +2264,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA2_X_LOC) let y := mload(SIGMA2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2056,8 +2279,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA3_X_LOC) let y := mload(SIGMA3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2072,8 +2294,7 @@ abstract contract BaseUltraVerifier { let x := mload(SIGMA4_X_LOC) let y := mload(SIGMA4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2088,8 +2309,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE1_X_LOC) let y := mload(TABLE1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2104,8 +2324,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE2_X_LOC) let y := mload(TABLE2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2120,8 +2339,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE3_X_LOC) let y := mload(TABLE3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2136,8 +2354,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE4_X_LOC) let y := mload(TABLE4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2152,8 +2369,7 @@ abstract contract BaseUltraVerifier { let x := mload(TABLE_TYPE_X_LOC) let y := mload(TABLE_TYPE_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2168,8 +2384,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID1_X_LOC) let y := mload(ID1_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2184,8 +2399,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID2_X_LOC) let y := mload(ID2_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2200,8 +2414,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID3_X_LOC) let y := mload(ID3_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2216,8 +2429,7 @@ abstract contract BaseUltraVerifier { let x := mload(ID4_X_LOC) let y := mload(ID4_Y_LOC) let xx := mulmod(x, x, q) - // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + // Verification key fields verified to be on curve at contract deployment mstore(0x00, x) mstore(0x20, y) } @@ -2405,7 +2617,10 @@ abstract contract BaseUltraVerifier { // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - mstore(OPENING_COMMITMENT_SUCCESS_FLAG, success) + if iszero(success) { + mstore(0x0, OPENING_COMMITMENT_FAILED_SELECTOR) + revert(0x00, 0x04) + } } /** @@ -2420,13 +2635,16 @@ abstract contract BaseUltraVerifier { let y := mload(PI_Z_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q)) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } // compute zeta.[PI_Z] and add into accumulator mstore(0x40, zeta) - success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) + success := staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) @@ -2436,7 +2654,10 @@ abstract contract BaseUltraVerifier { let y := mload(PI_Z_OMEGA_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2464,7 +2685,10 @@ abstract contract BaseUltraVerifier { let y := mload(RECURSIVE_P1_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2478,7 +2702,10 @@ abstract contract BaseUltraVerifier { let y := mload(RECURSIVE_P2_Y_LOC) let xx := mulmod(x, x, q) // validate on curve - success := and(success, eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) + if iszero(eq(mulmod(y, y, q), addmod(mulmod(x, xx, q), 3, q))) { + mstore(0x0, POINT_NOT_ON_CURVE_SELECTOR) + revert(0x00, 0x04) + } mstore(0x00, x) mstore(0x20, y) } @@ -2498,10 +2725,9 @@ abstract contract BaseUltraVerifier { } if iszero(success) { - mstore(0x0, EC_SCALAR_MUL_FAILURE_SELECTOR) + mstore(0x0, PAIRING_PREAMBLE_FAILED_SELECTOR) revert(0x00, 0x04) } - mstore(PAIRING_PREAMBLE_SUCCESS_FLAG, success) } /** @@ -2526,18 +2752,12 @@ abstract contract BaseUltraVerifier { mstore(0x160, mload(G2X_Y1_LOC)) success := staticcall(gas(), 8, 0x00, 0x180, 0x00, 0x20) - mstore(PAIRING_SUCCESS_FLAG, success) - mstore(RESULT_FLAG, mload(0x00)) - } - if iszero( - and( - and(and(mload(PAIRING_SUCCESS_FLAG), mload(RESULT_FLAG)), mload(PAIRING_PREAMBLE_SUCCESS_FLAG)), - mload(OPENING_COMMITMENT_SUCCESS_FLAG) - ) - ) { - mstore(0x0, PROOF_FAILURE_SELECTOR) - revert(0x00, 0x04) + if iszero(and(success, mload(0x00))) { + mstore(0x0, PAIRING_FAILED_SELECTOR) + revert(0x00, 0x04) + } } + { mstore(0x00, 0x01) return(0x00, 0x20) // Proof succeeded! diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 300ec84bb10..c8929fe5337 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## [0.23.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.22.0...barretenberg.js-v0.23.0) (2024-02-07) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + +## [0.22.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.21.0...barretenberg.js-v0.22.0) (2024-02-06) + + +### ⚠ BREAKING CHANGES + +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) + +### Miscellaneous + +* **acir:** Move `is_recursive` flag to be part of the circuit definition ([#4221](https://github.com/AztecProtocol/aztec-packages/issues/4221)) ([9c965a7](https://github.com/AztecProtocol/aztec-packages/commit/9c965a7c9e652dfeaba2f09152e5db287407473d)) + ## [0.21.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.20.0...barretenberg.js-v0.21.0) (2024-01-30) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index cb561061d12..7a886782f54 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.21.0", + "version": "0.23.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/boxes/blank-react/src/contracts/src/main.nr b/boxes/blank-react/src/contracts/src/main.nr index 84750a2da70..89c80306529 100644 --- a/boxes/blank-react/src/contracts/src/main.nr +++ b/boxes/blank-react/src/contracts/src/main.nr @@ -1,12 +1,11 @@ contract Blank { use dep::aztec::{ - abi, oracle::{ get_public_key::get_public_key, }, protocol_types::address::AztecAddress }; - + #[aztec(private)] fn constructor() {} diff --git a/boxes/blank/src/contracts/src/main.nr b/boxes/blank/src/contracts/src/main.nr index 28647415a6b..c5ccfa0ff44 100644 --- a/boxes/blank/src/contracts/src/main.nr +++ b/boxes/blank/src/contracts/src/main.nr @@ -1,12 +1,11 @@ contract Blank { use dep::aztec::{ - abi, oracle::{ get_public_key::get_public_key, }, protocol_types::address::AztecAddress }; - + #[aztec(private)] fn constructor() {} diff --git a/boxes/package.json b/boxes/package.json index 9b0417032de..f5c77e660e7 100644 --- a/boxes/package.json +++ b/boxes/package.json @@ -19,6 +19,7 @@ "@aztec/bb.js": "portal:../barretenberg/ts", "@aztec/circuit-types": "portal:../yarn-project/circuit-types", "@aztec/ethereum": "portal:../yarn-project/ethereum", + "@aztec/protocol-contracts": "portal:../yarn-project/protocol-contracts", "@aztec/types": "portal:../yarn-project/types" } } diff --git a/boxes/token/src/contracts/src/main.nr b/boxes/token/src/contracts/src/main.nr index a6c67b253ed..6bef8316bea 100644 --- a/boxes/token/src/contracts/src/main.nr +++ b/boxes/token/src/contracts/src/main.nr @@ -21,7 +21,6 @@ contract Token { note_header::NoteHeader, utils as note_utils, }, - context::{PrivateContext, PublicContext, Context}, hash::{compute_secret_hash}, state_vars::{map::Map, public_state::PublicState, set::Set}, protocol_types::{ @@ -328,7 +327,11 @@ contract Token { ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); if (storage_slot == storage.pending_shields.get_storage_slot()) { - note_utils::compute_note_hash_and_nullifier(TransparentNote::deserialize_content, note_header, serialized_note) + note_utils::compute_note_hash_and_nullifier( + TransparentNote::deserialize_content, + note_header, + serialized_note + ) } else { note_utils::compute_note_hash_and_nullifier(TokenNote::deserialize_content, note_header, serialized_note) } diff --git a/boxes/token/src/contracts/src/types/balances_map.nr b/boxes/token/src/contracts/src/types/balances_map.nr index 3b4c0607528..286a7825645 100644 --- a/boxes/token/src/contracts/src/types/balances_map.nr +++ b/boxes/token/src/contracts/src/types/balances_map.nr @@ -1,7 +1,7 @@ use dep::std::option::Option; use dep::safe_math::SafeU120; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, + context::Context, hash::pedersen_hash, protocol_types::{ address::AztecAddress, diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 2b37f7139af..bdbf09c7ce4 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -70,6 +70,7 @@ __metadata: "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/types": "workspace:^" tslib: "npm:^2.4.0" languageName: node @@ -289,6 +290,7 @@ __metadata: koa-router: "npm:^12.0.0" leveldown: "npm:^6.1.1" levelup: "npm:^5.1.1" + lodash.chunk: "npm:^4.2.0" lodash.clonedeepwith: "npm:^4.5.0" memdown: "npm:^6.1.1" pako: "npm:^2.1.0" @@ -297,6 +299,18 @@ __metadata: languageName: node linkType: soft +"@aztec/protocol-contracts@portal:../yarn-project/protocol-contracts::locator=%40aztec%2Fboxes%40workspace%3A.": + version: 0.0.0-use.local + resolution: "@aztec/protocol-contracts@portal:../yarn-project/protocol-contracts::locator=%40aztec%2Fboxes%40workspace%3A." + dependencies: + "@aztec/circuits.js": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/types": "workspace:^" + lodash.omit: "npm:^4.5.0" + tslib: "npm:^2.4.0" + languageName: node + linkType: soft + "@aztec/types@portal:../yarn-project/types::locator=%40aztec%2Fboxes%40workspace%3A.": version: 0.0.0-use.local resolution: "@aztec/types@portal:../yarn-project/types::locator=%40aztec%2Fboxes%40workspace%3A." @@ -9476,6 +9490,13 @@ __metadata: languageName: node linkType: hard +"lodash.omit@npm:^4.5.0": + version: 4.5.0 + resolution: "lodash.omit@npm:4.5.0" + checksum: 3808b9b6faae35177174b6ab327f1177e29c91f1e98dcbccf13a72a6767bba337306449d537a4e0d8a33d2673f10d39bc732e30c4b803274ea0c1168ea60e549 + languageName: node + linkType: hard + "lodash.times@npm:^4.3.2": version: 4.3.2 resolution: "lodash.times@npm:4.3.2" diff --git a/build-system/scripts/ensure_repo b/build-system/scripts/ensure_repo index b71c0fabb2f..d5dc5d8d2c0 100755 --- a/build-system/scripts/ensure_repo +++ b/build-system/scripts/ensure_repo @@ -8,20 +8,18 @@ LIFECYCLE_POLICY='{ "rules": [ { "rulePriority": 1, - "description": "No more than 200 cache images.", + "description": "No more than 1000 images, regardless of tag status.", "selection": { - "tagStatus": "tagged", - "tagPrefixList": ["cache-"], + "tagStatus": "any", "countType": "imageCountMoreThan", - "countNumber": 200 + "countNumber": 1000 }, "action": { "type": "expire" } } ] -} -' +}' REPOSITORY=$1 REGION=$2 diff --git a/cspell.json b/cspell.json index c9298ca6640..299b4ccf203 100644 --- a/cspell.json +++ b/cspell.json @@ -168,6 +168,7 @@ "println", "productionify", "protobuf", + "protogalaxy", "proxied", "proxified", "proxify", @@ -229,6 +230,7 @@ "unshield", "unshielding", "unzipit", + "updateable", "upperfirst", "usecase", "usecases", diff --git a/docs/docs/developers/aztecjs/guides/call_view_function.md b/docs/docs/developers/aztecjs/guides/call_view_function.md new file mode 100644 index 00000000000..5fda30f7f2d --- /dev/null +++ b/docs/docs/developers/aztecjs/guides/call_view_function.md @@ -0,0 +1,15 @@ +--- +title: How to Call a View Function +--- + +This guide explains how to call a `view` function using [Aztec.js](../main.md). + +To do this from the CLI, go [here](../../sandbox/references/cli-commands.md#calling-an-unconstrained-view-function). + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); +const balance = await contract.methods.getBalance(wallet.getAddress()).view(); +console.log(`Account balance is ${balance}`); +``` diff --git a/docs/docs/developers/aztecjs/guides/create_account.md b/docs/docs/developers/aztecjs/guides/create_account.md new file mode 100644 index 00000000000..bf0913cba44 --- /dev/null +++ b/docs/docs/developers/aztecjs/guides/create_account.md @@ -0,0 +1,21 @@ +--- +title: How to Create a New Account +--- + +This guide explains how to create a new account using [Aztec.js](../main.md). + +To do this from the CLI, go [here](../../sandbox/references/cli-commands.md#creating-accounts). + +```typescript +import { getSchnorrAccount } from "@aztec/aztec.js"; +import { GrumpkinPrivateKey } from "@aztec/circuit-types"; + +const encryptionPrivateKey = GrumpkinPrivateKey.random(); +const signingPrivateKey = GrumpkinPrivateKey.random(); +const wallet = getSchnorrAccount( + pxe, + encryptionPrivateKey, + signingPrivateKey +).waitDeploy(); +console.log(`New account deployed at ${wallet.getAddress()}`); +``` \ No newline at end of file diff --git a/docs/docs/developers/aztecjs/guides/deploy_contract.md b/docs/docs/developers/aztecjs/guides/deploy_contract.md new file mode 100644 index 00000000000..499af437a94 --- /dev/null +++ b/docs/docs/developers/aztecjs/guides/deploy_contract.md @@ -0,0 +1,18 @@ +--- +title: How to Deploy a Contract +--- + +This guide explains how to deploy a smart contract using [Aztec.js](../main.md). + +To do this from the CLI, go [here](../../sandbox/references/cli-commands.md#deploying-a-token-contract). + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.deploy(wallet, MyContractArtifact, [ + ...constructorArgs, +]) + .send() + .deployed(); +console.log(`Contract deployed at ${contract.address}`); +``` \ No newline at end of file diff --git a/docs/docs/developers/aztecjs/guides/send_transaction.md b/docs/docs/developers/aztecjs/guides/send_transaction.md new file mode 100644 index 00000000000..8cebd8edd61 --- /dev/null +++ b/docs/docs/developers/aztecjs/guides/send_transaction.md @@ -0,0 +1,20 @@ +--- +title: How to Send a Transaction +--- + +This guide explains how to send a transaction using [Aztec.js](../main.md). + +To do this from the CLI, go [here](../../sandbox/references/cli-commands.md#sending-a-transaction). + +```typescript +import { Contract } from "@aztec/aztec.js"; + +const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); +const tx = await contract.methods + .transfer(amount, recipientAddress) + .send() + .wait(); +console.log( + `Transferred ${amount} to ${recipientAddress} on block ${tx.blockNumber}` +); +``` \ No newline at end of file diff --git a/docs/docs/developers/aztecjs/main.md b/docs/docs/developers/aztecjs/main.md index 531754b2992..6e75dd7e4a9 100644 --- a/docs/docs/developers/aztecjs/main.md +++ b/docs/docs/developers/aztecjs/main.md @@ -2,64 +2,23 @@ title: Aztec.js --- -If you are looking for the API reference, go [here](../../apis/aztec-js/index.md). +If you are looking for the Aztec.js API reference, go [here](../../apis/aztec-js/index.md). ## Introduction - 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/apis/pxe/interfaces/PXE) through a `PXE` implementation, allowing developers to easily register new accounts, deploy contracts, view functions, and send transactions. -## Usage - -### Create a new account - -```typescript -import { getSchnorrAccount } from "@aztec/aztec.js"; -import { GrumpkinPrivateKey } from "@aztec/circuit-types"; - -const encryptionPrivateKey = GrumpkinPrivateKey.random(); -const signingPrivateKey = GrumpkinPrivateKey.random(); -const wallet = getSchnorrAccount( - pxe, - encryptionPrivateKey, - signingPrivateKey -).waitDeploy(); -console.log(`New account deployed at ${wallet.getAddress()}`); -``` - -### Deploy a contract - -```typescript -import { Contract } from "@aztec/aztec.js"; - -const contract = await Contract.deploy(wallet, MyContractArtifact, [ - ...constructorArgs, -]) - .send() - .deployed(); -console.log(`Contract deployed at ${contract.address}`); -``` - -### Send a transaction +## Guides -```typescript -import { Contract } from "@aztec/aztec.js"; +- [How to create a new account](./guides/create_account.md) +- [How to deploy a smart contract](./guides/deploy_contract.md) +- [How to send a transaction](./guides/send_transaction.md) +- [How to call a view function](./guides/call_view_function.md) -const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); -const tx = await contract.methods - .transfer(amount, recipientAddress) - .send() - .wait(); -console.log( - `Transferred ${amount} to ${recipientAddress} on block ${tx.blockNumber}` -); -``` +## References -### Call a view function +- [Aztec.js Reference](../../apis/aztec-js/index.md) +- [Accounts Reference](../../apis/accounts/index.md) -```typescript -import { Contract } from "@aztec/aztec.js"; +## Tutorials -const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); -const balance = await contract.methods.getBalance(wallet.getAddress()).view(); -console.log(`Account balance is ${balance}`); -``` +- [An example of testing with Aztec.js](../tutorials/testing.md) diff --git a/docs/docs/developers/contracts/abi.md b/docs/docs/developers/contracts/abi.md deleted file mode 100644 index fe493910cec..00000000000 --- a/docs/docs/developers/contracts/abi.md +++ /dev/null @@ -1,22 +0,0 @@ -# Aztec Function ABIs - -Discuss: -- Public Inputs ABIs for functions. -- Args & args hashes -- return values and return values hashes -- etc. - - -## Limitations - -### Num reads and writes - -### Num function calls - -### Num logs - -### Num key pair validations - -### No gas or fees yet - -(See also [Limitations](../limitations/main.md)) \ No newline at end of file diff --git a/docs/docs/developers/contracts/artifacts.md b/docs/docs/developers/contracts/compiling_contracts/artifacts.md similarity index 100% rename from docs/docs/developers/contracts/artifacts.md rename to docs/docs/developers/contracts/compiling_contracts/artifacts.md diff --git a/docs/docs/developers/contracts/compiling.md b/docs/docs/developers/contracts/compiling_contracts/how_to_compile_contract.md similarity index 88% rename from docs/docs/developers/contracts/compiling.md rename to docs/docs/developers/contracts/compiling_contracts/how_to_compile_contract.md index 58c805006ec..6acdef15c66 100644 --- a/docs/docs/developers/contracts/compiling.md +++ b/docs/docs/developers/contracts/compiling_contracts/how_to_compile_contract.md @@ -1,6 +1,8 @@ -# Compiling contracts +--- +title: How to compile a contract +--- -Once you have written a [contract](../contracts/main.md) in Aztec.nr, you will need to compile it into an [artifact](./artifacts.md) in order to use it. +Once you have written a [contract](../main.md) in Aztec.nr, you will need to compile it into an [artifact](./artifacts.md) in order to use it. In this guide we will cover how to do so, both using the CLI and programmatically. @@ -10,7 +12,7 @@ We'll also cover how to generate a helper [TypeScript interface](#typescript-int To compile a contract using the Aztec's build of nargo. -Run the `aztec-nargo compile` command within your [contract project folder](./layout.md#directory-structure), which is the one that contains the `Nargo.toml` file: +Run the `aztec-nargo compile` command within your [contract project folder](../writing_contracts/layout.md), which is the one that contains the `Nargo.toml` file: ```bash aztec-nargo compile @@ -111,11 +113,11 @@ export class TokenContract extends ContractBase { } ``` -Read more about interacting with contracts using `aztec.js` [here](../getting_started/aztecjs-getting-started.md). +Read more about interacting with contracts using `aztec.js` [here](../../getting_started/aztecjs-getting-started.md). ### Aztec.nr interfaces -An Aztec.nr contract can [call a function](./syntax/functions/main.md) in another contract via `context.call_private_function` or `context.call_public_function`. However, this requires manually assembling the function selector and manually serializing the arguments, which is not type-safe. +An Aztec.nr contract can [call a function](../writing_contracts/functions/call_functions.md) in another contract via `context.call_private_function` or `context.call_public_function`. However, this requires manually assembling the function selector and manually serializing the arguments, which is not type-safe. To make this easier, the compiler can generate contract interface structs that expose a convenience method for each function listed in a given contract artifact. These structs are intended to be used from another contract project that calls into the current one. For each contract, two interface structs are generated: one to be used from private functions with a `PrivateContext`, and one to be used from open functions with a `PublicContext`. @@ -209,7 +211,7 @@ impl TokenPublicContextInterface { } ``` -Read more about how to use the Aztec.nr interfaces [here](./syntax/functions/main.md). +Read more about how to use the Aztec.nr interfaces [here](../writing_contracts/functions/main.md). :::info At the moment, the compiler generates these interfaces from already compiled ABIs, and not from source code. This means that you should not import a generated interface from within the same project as its source contract, or you risk circular references. @@ -217,7 +219,7 @@ At the moment, the compiler generates these interfaces from already compiled ABI ## Next steps -Once you have compiled your contracts, you can use the generated artifacts via the `Contract` class in the `aztec.js` package to deploy and interact with them, or rely on the type-safe typescript classes directly. Alternatively, use the CLI [to deploy](../../developers/cli/main.md#deploying-a-token-contract) and [interact](../../developers/cli/main.md#sending-a-transaction) with them. +Once you have compiled your contracts, you can use the generated artifacts via the `Contract` class in the `aztec.js` package to deploy and interact with them, or rely on the type-safe typescript classes directly. Alternatively, use the CLI [to deploy](../../sandbox/references/cli-commands.md#deploying-a-token-contract) and [interact](../../sandbox/references/cli-commands.md#calling-an-unconstrained-view-function) with them. -import Disclaimer from "../../misc/common/\_disclaimer.mdx"; +import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; diff --git a/docs/docs/developers/contracts/deploying.md b/docs/docs/developers/contracts/deploying_contracts/how_to_deploy_contract.md similarity index 85% rename from docs/docs/developers/contracts/deploying.md rename to docs/docs/developers/contracts/deploying_contracts/how_to_deploy_contract.md index ec9d88ef1f4..9da2f49e057 100644 --- a/docs/docs/developers/contracts/deploying.md +++ b/docs/docs/developers/contracts/deploying_contracts/how_to_deploy_contract.md @@ -1,12 +1,16 @@ +--- +title: How to deploy a contract +--- + # Deploying contracts -Once you have [compiled](./compiling.md) your contracts you can proceed to deploying them using the aztec-cli or using aztec.js which is a Typescript client to interact with the sandbox. +Once you have [compiled](../compiling_contracts/how_to_compile_contract.md) your contracts you can proceed to deploying them using the aztec-cli or using aztec.js which is a Typescript client to interact with the sandbox. ## Prerequisites -- `aztec-cli` and `aztec-nargo` installed (go to [CLI main section](../cli/main.md) for installation instructions) -- contract artifacts ready (go to [Compiling contracts section](./compiling.md) for instructions on how to compile contracts) -- Aztec Sandbox running (go to [Sandbox section](../getting_started/quickstart.md) for instructions on how to install and run the sandbox) +- `aztec-cli` and `aztec-nargo` installed (go to [Sandbox and CLI section](../../sandbox/main.md) for installation instructions) +- contract artifacts ready (go to [How to Compile Contract](../compiling_contracts/how_to_compile_contract.md) for instructions on how to compile contracts) +- Aztec Sandbox running (go to [Sandbox section](../../getting_started/quickstart.md) for instructions on how to install and run the sandbox) ## Deploy @@ -39,7 +43,7 @@ Generate the typescript class: aztec-cli codegen ./aztec-nargo/output/target/path -o src/artifacts --ts ``` -This would create a typescript file like `Example.ts` in `./src/artifacts`. Read more on the [compiling page](./compiling.md). +This would create a typescript file like `Example.ts` in `./src/artifacts`. Read more on the [compiling page](../compiling_contracts/how_to_compile_contract.md). Now you can import it to easily deploy and interact with the contract. @@ -84,7 +88,7 @@ Its arguments are `PXE` client and contract constructor arguments. Additionally the `.send()` method can have a few optional arguments too, which are specified in an optional object: -- `portalContract?: EthAddress`: The L1 portal address to link the contract to. See the section on [Portals to learn more about them](./portals/main.md). +- `portalContract?: EthAddress`: The L1 portal address to link the contract to. See the section on [Portals to learn more about them](../writing_contracts/portals/portals.md). - `contractAddressSalt?: Fr`: A salt which is one of the inputs when computing a contract address of the contract to be deployed. By default is set to a random value. Set it, if you need a deterministic contract address (same functionality as Ethereum's `CREATE2` opcode). diff --git a/docs/docs/developers/contracts/main.md b/docs/docs/developers/contracts/main.md index 40f7a53af9d..37af0bb5c9f 100644 --- a/docs/docs/developers/contracts/main.md +++ b/docs/docs/developers/contracts/main.md @@ -1,6 +1,10 @@ -import DocCardList from '@theme/DocCardList'; +--- +title: Smart Contracts +--- -# Aztec.nr +This section is a collection of how-to guides and references for building smart contracts with Aztec.nr. + +If you are looking for an overview of how smart contracts work, head to the [Concepts section](../../learn/concepts/smart_contracts/main.md). ## What is Aztec.nr? @@ -8,7 +12,7 @@ import DocCardList from '@theme/DocCardList'; ## Nomenclature -[**Noir**](https://noir-lang.org/) is a domain specific language for creating and verifying proofs. It's design choices are influenced heavily by Rust. +[**Noir**](https://noir-lang.org/) is a domain specific language for creating and verifying proofs. Its design choices are influenced heavily by Rust. A **smart contract** is just a collection of persistent state variables, and a collection of functions which may edit those state variables. @@ -20,7 +24,7 @@ An **Aztec smart contract** is a smart contract with **private** state variables ## Install aztec-nargo -To write an Aztec.nr contract, you need to the compiler, `aztec-nargo` which is installed when you install the sandbox. See install instructions [here](../cli/sandbox-reference.md). +To write an Aztec.nr contract, you need to the compiler, `aztec-nargo` which is installed when you install the sandbox. See install instructions [here](../sandbox/references/sandbox-reference.md). :::info For those coming from vanilla Noir, the version used for aztec.nr is tracked separately to nargo for vanilla Noir. Be sure to use `aztec-nargo` to compile your contracts. @@ -44,7 +48,7 @@ There are a number of tools to make writing Aztec.nr contracts in Noir more plea ## Tutorials -See the [Token Contract tutorial](../tutorials/writing_token_contract.md) for more info on getting set up to write contracts. +See the [Private Voting tutorial](../tutorials/writing_private_voting_contract.md) for more info on getting set up to write contracts. ## Learn more diff --git a/docs/docs/developers/contracts/syntax/globals.md b/docs/docs/developers/contracts/references/globals.md similarity index 92% rename from docs/docs/developers/contracts/syntax/globals.md rename to docs/docs/developers/contracts/references/globals.md index 1778c75e56d..4f66ff577a6 100644 --- a/docs/docs/developers/contracts/syntax/globals.md +++ b/docs/docs/developers/contracts/references/globals.md @@ -9,7 +9,7 @@ For developers coming from solidity, this concept will be similar to how the glo `Aztec` has two execution environments, Private and Public. Each execution environment contains a different global variables object. ## Private Global Variables -#include_code private-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code private-global-variables /yarn-project/aztec-nr/aztec/src/context/globals/private_global_variables.nr rust The private global variables contain: ### Chain Id @@ -27,7 +27,7 @@ context.version(); ## Public Global Variables -#include_code public-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code global-variables /yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr rust The public global variables contain the values present in the `private global variables` described above, with the addition of: diff --git a/docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md b/docs/docs/developers/contracts/references/history_lib_reference.md similarity index 60% rename from docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md rename to docs/docs/developers/contracts/references/history_lib_reference.md index d7688909262..5928a54275b 100644 --- a/docs/docs/developers/contracts/syntax/historical_access/history_lib_reference.md +++ b/docs/docs/developers/contracts/references/history_lib_reference.md @@ -6,53 +6,57 @@ title: History Reference ## Note inclusion -Note inclusion proves that a note existed (its hash was included in a note hash tree) at a specific block number. +Note inclusion proves that a note existed (its hash was included in a note hash tree) at a specific block number. There exists a version that tests for note inclusion at current block number. It is recommended to use this version whenever possible to reduce cost. -## prove_note_inclusion +### prove_note_inclusion -`prove_note_inclusion` takes 4 parameters: +`prove_note_inclusion_at` takes 3 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| -| note_interface | NoteInterface | Interface for the note with necessary functionality| | note_with_header| Note | The note you are proving inclusion for | | block_number | u32 | Block number for proving note's existence | | context | PrivateContext | Private context | ## prove_note_commitment_inclusion -A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](../../../../learn/concepts/storage/trees/main.md#example-note). +A **commitment**, also referred to as a **note hash** is a public acknowledgment of the existence of a note without revealing the content of the note. You can learn more about how to compress a note to a note hash [here](../../../learn/concepts/storage/trees/main.md#example-note). -`prove_note_commitment_inclusion` takes 3 parameters: +`prove_note_commitment_inclusion` takes 2 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| -| commitment | Field | Note commitment we are checking inclusion of | -| block_number | u32 | Block number for proving note's existence | -| context| PrivateContext | Private Context | +| note_with_header| Note | The note you are proving inclusion for | +| context | PrivateContext | Private context | ## Note validity -This proves that a note exists and has not been nullified at a specified block. +This proves that a note exists and has not been nullified at a specified block. Again as above, there exists a version that tests for validity at current block. It is recommended to use this version whenever possible to reduce cost. ### prove_note_validity -`prove_note_validity` takes 4 parameters: +`prove_note_validity_at` takes 3 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| -| note_interface | NoteInterface | Interface for the note with necessary functionality| | note_with_header| Note | The note you are proving inclusion for | | block_number | u32 | Block number for proving note's existence | | context | PrivateContext | Private context | +`prove_note_validity` takes 2 parameters: + +| Name | Type | Description | +|-----------------|------------------------|-----------------------------------------------------| +| note_with_header| Note | The note you are proving inclusion for | +| context | PrivateContext | Private context | + ## Nullifier inclusion -This proves that a nullifier was included in a certain block (can be used to prove that a note had been nullified). +This proves that a nullifier was included in a certain block (can be used to prove that a note had been nullified). The same disclaimer above holds true for this, and subsequent functions that specify another version without a block_number argument. ### prove_nullifier_inclusion -`prove_nullifier_inclusion` takes 3 parameters: +`prove_nullifier_inclusion_at` takes 3 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| @@ -60,22 +64,39 @@ This proves that a nullifier was included in a certain block (can be used to pro | block_number | u32 | Block number for proving note's existence | | context | PrivateContext | Private context | +`prove_nullifier_inclusion` takes 2 parameters: + +| Name | Type | Description | +|-----------------|------------------------|-----------------------------------------------------| +| nullifier | Field | The nullifier you are proving inclusion for | +| context | PrivateContext | Private context | + +### prove_note_is_nullified_at / prove_note_is_nullified + +Instead of passing the nullifier, you can check that a note has been nullified by passing the note. + ## Nullifier non inclusion This proves that a nullifier was not included in a certain block (can be used to prove that a note had not yet been nullified in a given block). -### prove_nullifier_non_inclusion +### prove_nullifier_not_included -`prove_nullifier_non_inclusion` takes 3 parameters: +`prove_nullifier_not_included_at` takes 3 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| | nullifier | Field | The nullifier you are proving inclusion for | | block_number | u32 | Block number for proving note's existence | | context | PrivateContext | Private context | - - -### note_not_nullified + +`prove_nullifier_not_included` takes 2 parameters: + +| Name | Type | Description | +|-----------------|------------------------|-----------------------------------------------------| +| nullifier | Field | The nullifier you are proving inclusion for | +| context | PrivateContext | Private context | + +### prove_note_not_nullified_at / prove_note_not_nullified Instead of passing the nullifier, you can check that a note has not been nullified by passing the note. @@ -85,7 +106,7 @@ This proves that a public value exists at a certain block. ### prove_public_value_inclusion -`prove_public_value_inclusion` takes 4 parameters: +`prove_public_value_inclusion_at` takes 4 parameters: | Name | Type | Description | |-----------------|------------------------|-----------------------------------------------------| @@ -94,13 +115,21 @@ This proves that a public value exists at a certain block. | block_number | u32 | Block number for proving value's existence | | context | PrivateContext | Private context | +`prove_public_value_inclusion` takes 3 parameters: + +| Name | Type | Description | +|-----------------|------------------------|-----------------------------------------------------| +| value | Field | The public value you are proving inclusion for | +| storage_slot | Field | Storage slot the value exists in | +| context | PrivateContext | Private context | + ## Contract inclusion This proves that a contract exists in, ie had been deployed before or in, a certain block. ### prove_contract_inclusion -`prove_contract_inclusion` takes 7 parameters: +`prove_contract_inclusion_at` takes 7 parameters: | Name | Type | Description | |---------------------------|-----------------|-------------------------------------------------------| diff --git a/docs/docs/developers/contracts/portals/data_structures.md b/docs/docs/developers/contracts/references/portals/data_structures.md similarity index 100% rename from docs/docs/developers/contracts/portals/data_structures.md rename to docs/docs/developers/contracts/references/portals/data_structures.md diff --git a/docs/docs/developers/contracts/portals/inbox.md b/docs/docs/developers/contracts/references/portals/inbox.md similarity index 100% rename from docs/docs/developers/contracts/portals/inbox.md rename to docs/docs/developers/contracts/references/portals/inbox.md diff --git a/docs/docs/developers/contracts/portals/outbox.md b/docs/docs/developers/contracts/references/portals/outbox.md similarity index 100% rename from docs/docs/developers/contracts/portals/outbox.md rename to docs/docs/developers/contracts/references/portals/outbox.md diff --git a/docs/docs/developers/contracts/portals/registry.md b/docs/docs/developers/contracts/references/portals/registry.md similarity index 100% rename from docs/docs/developers/contracts/portals/registry.md rename to docs/docs/developers/contracts/references/portals/registry.md diff --git a/docs/docs/developers/contracts/references/slow_updates_tree.md b/docs/docs/developers/contracts/references/slow_updates_tree.md new file mode 100644 index 00000000000..552530edeb7 --- /dev/null +++ b/docs/docs/developers/contracts/references/slow_updates_tree.md @@ -0,0 +1,123 @@ +--- +title: Slow Updates Tree +--- + +## Struct `SlowMap` + +### Overview +The `SlowMap` struct is used to interact with a slow updates tree deployed via the SlowTree smart contract. + +### Fields + +| Name | Type | Description | +|---------|-----------|---------------------------------| +| address | `Field` | The address of the SlowTree contract | + +## Functions + +### at + +Returns an instance of `SlowMap` at the specified address. + +**Parameters** + +| Name | Type | Description | +|----------|----------------|----------------------------| +| `address`| `AztecAddress` | The address of the SlowTree | + +**Return** + +| Name | Type | Description | +|-------|-----------|------------------------------| +| - | `SlowMap` | The `SlowMap` instance | + +**Example** + +#include_code slowmap_at yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +### initialize + +Initializes the `SlowMap`. + +**Parameters** + +| Name | Type | Description | +|-----------|-----------------|----------------------| +| `context` | `PublicContext` | The execution context | + +**Return** + +| Name | Type | Description | +|------|------|-------------| +| - | - | - | + +**Example** + +#include_code slowmap_initialize yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +### read_at_pub + +Reads a value at a specified index from a public function. + +**Parameters** + +| Name | Type | Description | +|-----------|-----------------|-----------------------| +| `context` | `PublicContext` | The execution context | +| `index` | `Field` | The index to read at | + +**Return** + +| Name | Type | Description | +|----------|--------|-----------------------| +| `result` | `Field`| The value at `index` | + +**Example** + +#include_code read_at_pub yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +### read_at + +Reads a value at a specified index from a private function. + +**Parameters** + +| Name | Type | Description | +|-----------|--------------------|------------------------| +| `context` | `PrivateContext` | The execution context | +| `index` | `Field` | The index to read at | + +**Return** + +| Name | Type | Description | +|----------|--------|-----------------------| +| `result` | `Field`| The value at `index` | + +**Example** + +#include_code slowmap_read_at yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +### update_at_private + +Updates a value at a specified index from a private function. Does not return anything. + +**Parameters** + +| Name | Type | Description | +|-------------|--------------------|------------------------| +| `context` | `PrivateContext` | The execution context | +| `index` | `Field` | The index to update | +| `new_value` | `Field` | The new value | + +**Example** + +#include_code get_and_update_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +## Updating from public + +This is not a method in the interface as it can be done using regular Aztec.nr public storage update syntax. + +**Example** + +#include_code write_slow_update_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + diff --git a/docs/docs/developers/contracts/references/storage/main.md b/docs/docs/developers/contracts/references/storage/main.md new file mode 100644 index 00000000000..d16a1d1d69f --- /dev/null +++ b/docs/docs/developers/contracts/references/storage/main.md @@ -0,0 +1,481 @@ +# Writing a token contract in Aztec.nr + +In this tutorial we will go through writing an L2 native token contract +for the Aztec Network, using the Aztec.nr contract libraries. It is recommended that you go through the [the introduction to contracts](../../main.md) and [setup instructions](../../setup.md) section before this tutorial to gain some familiarity with writing Aztec smart contracts. + +This tutorial is intended to help you get familiar with the Aztec.nr library, Aztec contract syntax and some of the underlying structure of the Aztec network. + +In this tutorial you will learn how to: + +- Write public functions that update public state +- Write private functions that update private state +- Implement access control on public and private functions +- Handle math operations safely +- Handle different private note types +- Pass data between private and public state + +We are going to start with a blank project and fill in the token contract source code defined on Github [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-contracts/contracts/token_contract/src/main.nr), and explain what is being added as we go. + +## Requirements + +You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](../../../sandbox/references/sandbox-reference.md) for installation instructions. + +You should also install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) for VS Code. + +Check the [Dev Tools section](https://github.com/noir-lang/awesome-noir#dev-tools) of the awesome-noir repo for language support for additional editors (Vim, emacs, tree-sitter, etc). + +## Project setup + +Create a new directory called `token_contract_tutorial` + +```bash +mkdir token_contract_tutorial +``` + +inside that directory, create a `contracts` folder for the Aztec contracts. + +```bash +cd token_contract_tutorial && mkdir contracts && cd contracts +``` + +Create the following file structure + +```tree +. +└── contracts + ├── Nargo.toml + └── src + └── main.nr +``` + +Add the following content to Nargo.toml file: + +```toml +[package] +name = "token_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/aztec" } +safe_math = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/safe-math"} +authwit={ git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/authwit"} +compressed_string = {git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/compressed-string"} +``` + +## Contract Interface + +```rust +contract Token { + #[aztec(private)] + fn constructor() {} + + #[aztec(public)] + fn set_admin(new_admin: AztecAddress) {} + + #[aztec(public)] + fn set_minter(minter: AztecAddress, approve: bool) {} + + #[aztec(public)] + fn mint_public(to: AztecAddress, amount: Field) -> Field {} + + #[aztec(public)] + fn mint_private(amount: Field, secret_hash: Field) -> Field {} + + #[aztec(public)] + fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) -> Field {} + + #[aztec(public)] + fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} + + #[aztec(public)] + fn burn_public(from: AztecAddress, amount: Field, nonce: Field) -> Field {} + + // Private functions + + #[aztec(private)] + fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) -> Field {} + + #[aztec(private)] + fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} + + #[aztec(private)] + fn transfer(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} + + #[aztec(private)] + fn burn(from: AztecAddress, amount: Field, nonce: Field) -> Field {} + + // Internal functions below + + // Will be internal in the future + #[aztec(public)] + fn _initialize(new_admin: AztecAddress) {} + + #[aztec(public)] + internal fn _increase_public_balance(to: AztecAddress, amount: Field) {} + + #[aztec(public)] + internal fn _reduce_total_supply(amount: Field) {} + + // Unconstrained functions (read only) + + unconstrained fn admin() -> Field {} + + unconstrained fn is_minter(minter: AztecAddress) -> bool {} + + unconstrained fn total_supply() -> Field {} + + unconstrained fn balance_of_private(owner: AztecAddress) -> Field {} + + unconstrained fn balance_of_public(owner: AztecAddress) -> Field {} + + unconstrained fn compute_note_hash_and_nullifier(contract_address: Field, nonce: Field, storage_slot: Field, serialized_note: [Field; VALUE_NOTE_LEN]) -> [Field; 4] {} +} +``` + +This specifies the interface of the `Token` contract. Go ahead and copy and paste this interface into your `main.nr` file. + +Before we through the interface and implement each function, let's review the functions to get a sense of what the contract does. + +### Constructor interface + +There is a `constructor` function that will be executed once, when the contract is deployed, similar to the constructor function in Solidity. This is marked private, so the function logic will not be transparent. To execute public function logic in the constructor, this function will call `_initialize` (marked internal, more detail below). + +### Public functions + +These are functions that have transparent logic, will execute in a publicly verifiable context and can update public storage. + +- `set_admin` enables the admin to be updated +- `set_minter` enables accounts to be added / removed from the approved minter list +- `mint_public` enables tokens to be minted to the public balance of an account +- `mint_private` enables tokens to be minted to the private balance of an account (with some caveats we will dig into) +- `shield` enables tokens to be moved from a public balance to a private balance, not necessarily the same account (step 1 of a 2 step process) +- `transfer_public` enables users to transfer tokens from one account's public balance to another account's public balance +- `burn_public` enables users to burn tokens + +### Private functions + +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](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](../../../../learn/concepts/storage/trees/main.md#nullifier-tree), 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. + +- `redeem_shield` enables accounts to claim tokens that have been made private via `mint_private` or `shield` by providing the secret +- `unshield` enables an account to send tokens from their private balance to any other account's public balance +- `transfer` enables an account to send tokens from their private balance to another account's private balance +- `burn` enables tokens to be burned privately + +### Internal functions + +Internal functions are functions that can only be called by the contract itself. These can be used when the contract needs to call one of it's public functions from one of it's private functions. + +- `_initialize` is a way to call a public function from the `constructor` (which is a private function) +- `_increase_public_balance` increases the public balance of an account when `unshield` is called +- `_reduce_total_supply` reduces the total supply of tokens when a token is privately burned + +To clarify, let's review some details of the Aztec transaction lifecycle, particularly how a transaction "moves through" these contexts. + +#### Execution contexts + +Transactions are initiated in the private context, then move to the L2 public context, then to the Ethereum L1 context. + +Step 1. Private Execution + +Users provide inputs and execute locally on a their device for privacy reasons. Outputs of the private execution are commitment and nullifier updates, a proof of correct execution and any return data to pass to the public execution context. + +Step 2. Public Execution + +This happens remotely by the sequencer, which takes inputs from the private execution and runs the public code in the network virtual machine, similar to any other public blockchain. + +Step 3. Ethereum execution + +Aztec transactions can pass data to Ethereum contracts through the rollup via the outbox. The data can consumed by Ethereum contracts at a later time, but this is not part of the transaction flow for an Aztec transaction. The technical details of this are beyond the scope of this tutorial, but we will cover them in an upcoming piece. + +### Unconstrained functions + +Unconstrained functions can be thought of as view functions from Solidity--they only return information from the contract storage or compute and return data without modifying contract storage. + +The `compute_note_hash_and_nullifier` function allows contract devs to specify how to compute notes and nullifiers. This must be included in every contract because it depends on the storage slots, which are defined when we set up storage. + +## Contract dependencies + +Before we can implement the functions, we need set up the contract storage, and before we do that we need to import the appropriate dependencies. + +:::info Copy required files + +We will be going over the code in `main.nr` [here](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/noir-contracts/contracts/token_contract/src). If you are following along and want to compile `main.nr` yourself, you need to add the other files in the directory as they contain imports that are used in `main.nr`. + +::: + +Just below the contract definition, add the following imports: + +#include_code imports /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +We are importing the Option type, items from the `value_note` library to help manage private value storage, note utilities, context (for managing private and public execution contexts), `state_vars` for helping manage state, `types` for data manipulation and `oracle` for help passing data from the private to public execution context. We also import the `auth` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/auth.nr) to handle token authorizations from [Account Contracts](../../../../learn/concepts/accounts/main.md). Check out the Account Contract with AuthWitness [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr). + +[SafeU120](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/safe-math/src/safe_u120.nr) is a library to do safe math operations on unsigned integers that protects against overflows and underflows. + +For more detail on execution contexts, see [Contract Communication](../../../../learn/concepts/communication/main). + +### Types files + +We are also importing types from a `types.nr` file, which imports types from the `types` folder. You can view them [here](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/noir-contracts/contracts/token_contract/src). + +The main thing to note from this types folder is the `TransparentNote` definition. This defines how the contract moves value from the public domain into the private domain. It is similar to the `value_note` that we imported, but with some modifications namely, instead of a defined `owner`, it allows anyone that can produce the pre-image to the stored `secret_hash` to spend the note. + +### Note on private state + +Private state in Aztec is all [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output) under the hood. Handling UTXOs is largely abstracted away from developers, but there are some unique things for developers to be aware of when creating and managing private state in an Aztec contract. See [State Variables](../storage/main.md) to learn more about public and private state in Aztec. + +## Contract Storage + +Now that we have dependencies imported into our contract we can define the storage for the contract. + +Below the dependencies, paste the following Storage struct: + +#include_code storage_struct /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +Reading through the storage variables: + +- `admin` a single Field value stored in public state. A `Field` is basically an unsigned integer with a maximum value determined by the underlying cryptographic curve. +- `minters` is a mapping of Fields in public state. This will store whether an account is an approved minter on the contract. +- `balances` is a mapping of private balances. Private balances are stored in a `Set` of `ValueNote`s. The balance is the sum of all of an account's `ValueNote`s. +- `total_supply` is a Field value stored in public state and represents the total number of tokens minted. +- `pending_shields` is a `Set` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. +- `public_balances` is a mapping field elements in public state and represents the publicly viewable balances of accounts. + +You can read more about it [here](../storage/main.md). + +## Functions + +Copy and paste the body of each function into the appropriate place in your project if you are following along. + +### Constructor + +In the source code, the constructor logic is commented out due to some limitations of the current state of the development. + +#include_code constructor /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +The constructor is a private function. There isn't any private state to set up in this function, but there is public state to set up. The `context` is a global variable that is available to private and public functions, but the available methods differ based on the context. You can see the implementation details [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/context.nr). The `context.call_public_function` allows a private function to call a public function on any contract. In this case, the constructor is passing the `msg_sender` as the argument to the `_initialize` function, which is also defined in this contract. + +### Public function implementations + +Public functions are declared with the `#[aztec(public)]` macro above the function name like so: + +#include_code set_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +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 prepare data to be used in a private context, as we will go over below (e.g. see the [shield](#shield) function). + +Storage is referenced as `storage.variable`. + +#### `set_admin` + +After storage is initialized, the contract checks that the `msg_sender` is the `admin`. If not, the transaction will fail. If it is, the `new_admin` is saved as the `admin`. + +#include_code set_admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `set_minter` + +This function allows the `admin` to add or a remove a `minter` from the public `minters` mapping. It checks that `msg_sender` is the `admin` and finally adds the `minter` to the `minters` mapping. + +#include_code set_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `mint_public` + +This function allows an account approved in the public `minters` mapping to create new public tokens owned by the provided `to` address. + +First, storage is initialized. Then the function checks that the `msg_sender` is approved to mint in the `minters` mapping. If it is, a new `SafeU120` value is created of the `amount` provided. The function reads the recipients public balance and then adds the amount to mint, saving the output as `new_balance`, then reads to total supply and adds the amount to mint, saving the output as `supply`. `new_balance` and `supply` are then written to storage. + +The function returns 1 to indicate successful execution. + +#include_code mint_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `mint_private` + +This public function allows an account approved in the public `minters` mapping to create new private tokens that can be claimed by anyone that has the pre-image to the `secret_hash`. + +First, public storage is initialized. Then it checks that the `msg_sender` is an approved minter. Then a new `TransparentNote` is created with the specified `amount` and `secret_hash`. You can read the details of the `TransparentNote` in the `types.nr` file [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/noir-contracts/contracts/token_contract/src/types.nr#L61). The `amount` is added to the existing public `total_supply` and the storage value is updated. Then the new `TransparentNote` is added to the `pending_shields` using the `insert_from_public` function, which is accessible on the `Set` type. Then it's ready to be claimed by anyone with the `secret_hash` pre-image using the `redeem_shield` function. It returns `1` to indicate successful execution. + +#include_code mint_private /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `shield` + +This public function enables an account to stage tokens from it's `public_balance` to be claimed as a private `TransparentNote` by any account that has the pre-image to the `secret_hash`. + +First, storage is initialized. Then it checks whether the calling contract (`context.msg_sender`) matches the account that the funds will be debited from. + +##### Authorizing token spends + +If the `msg_sender` is **NOT** the same as the account to debit from, the function checks that the account has authorized the `msg_sender` contract to debit tokens on its behalf. This check is done by computing the function selector that needs to be authorized (in this case, the `shield` function), computing the hash of the message that the account contract has approved. This is a hash of the contract that is approved to spend (`context.msg_sender`), the token contract that can be spent from (`context.this_address()`), the `selector`, the account to spend from (`from.address`), the `amount`, the `secret_hash` and a `nonce` to prevent multiple spends. This hash is passed to `assert_valid_public_message_for` to ensure that the Account Contract has approved tokens to be spent on it's behalf. + +If the `msg_sender` is the same as the account to debit tokens from, the authorization check is bypassed and the function proceeds to update the account's `public_balance` and adds a new `TransparentNote` to the `pending_shields`. + +It returns `1` to indicate successful execution. + +#include_code shield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `transfer_public` + +This public function enables public transfers between Aztec accounts. The sender's public balance will be debited the specified `amount` and the recipient's public balances will be credited with that amount. + +After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender and recipient's balances are updated and saved to storage using the `SafeU120` library. + +#include_code transfer_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `burn_public` + +This public function enables public burning (destroying) of tokens from the sender's public balance. + +After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender's public balance and the `total_supply` are updated and saved to storage using the `SafeU120` library. + +#include_code burn_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### Private function implementations + +Private functions are declared with the `#[aztec(private)]` macro above the function name like so: + +```rust + #[aztec(private)] + fn redeem_shield( +``` + +As described in the [execution contexts section above](#execution-contexts), private function logic and transaction information is hidden from the world and is executed on user devices. Private functions update private state, but can pass data to the public execution context (e.g. see the [`unshield`](#unshield) function). + +Storage is referenced as `storage.variable`. + +#### `redeem_shield` + +This private function enables an account to move tokens from a `TransparentNote` in the `pending_shields` mapping to any Aztec account as a `ValueNote` in private `balances`. + +Going through the function logic, first the `secret_hash` is generated from the given secret. This ensures that only the entity possessing the secret can use it to redeem the note. Following this, a `TransparentNote` is retrieved from the set, using the provided amount and secret. The note is subsequently removed from the set, allowing it to be redeemed only once. The recipient's private balance is then increased using the `increment` helper function from the `value_note` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/value-note/src/utils.nr). + +The function returns `1` to indicate successful execution. + +#include_code redeem_shield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `unshield` + +This private function enables un-shielding of private `ValueNote`s stored in `balances` to any Aztec account's `public_balance`. + +After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After the authorization check, the sender's private balance is decreased using the `decrement` helper function for the `value_note` library. Then it stages a public function call on this contract ([`_increase_public_balance`](#_increase_public_balance)) to be executed in the [public execution phase](#execution-contexts) of transaction execution. `_increase_public_balance` is marked as an `internal` function, so can only be called by this token contract. + +The function returns `1` to indicate successful execution. + +#include_code unshield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `transfer` + +This private function enables private token transfers between Aztec accounts. + +After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After authorization, the function gets the current balances for the sender and recipient and decrements and increments them, respectively, using the `value_note` helper functions. + +#include_code transfer /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `burn` + +This private function enables accounts to privately burn (destroy) tokens. + +After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. Then it gets the sender's current balance and decrements it. Finally it stages a public function call to [`_reduce_total_supply`](#_reduce_total_supply). + +#include_code burn /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### Internal function implementations + +Internal functions are functions that can only be called by this contract. The following 3 functions are public functions that are called from the [private execution context](#execution-contexts). Marking these as `internal` ensures that only the desired private functions in this contract are able to call them. Private functions defer execution to public functions because private functions cannot update public state directly. + +#### `_initialize` + +This function is called via the [constructor](#constructor). + +This function sets the creator of the contract (passed as `msg_sender` from the constructor) as the admin and makes them a minter. + +#include_code initialize /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `_increase_public_balance` + +This function is called from [`unshield`](#unshield). The account's private balance is decremented in `shield` and the public balance is increased in this function. + +#include_code increase_public_balance /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `_reduce_total_supply` + +This function is called from [`burn`](#burn). The account's private balance is decremented in `burn` and the public `total_supply` is reduced in this function. + +#include_code reduce_total_supply /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +### Unconstrained function implementations + +Unconstrained functions are similar to `view` functions in Solidity in that they only return information from the contract storage or compute and return data without modifying contract storage. + +#### `admin` + +A getter function for reading the public `admin` value. + +#include_code admin /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `is_minter` + +A getter function for checking the value of associated with a `minter` in the public `minters` mapping. + +#include_code is_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `total_supply` + +A getter function for checking the token `total_supply`. + +#include_code total_supply /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `balance_of_private` + +A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have access to the `owner`s decryption keys in order to decrypt their notes. + +#include_code balance_of_private /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `balance_of_public` + +A getter function for checking the public balance of the provided Aztec account. + +#include_code balance_of_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +#### `compute_note_hash_and_nullifier` + +A getter function to compute the note hash and nullifier for notes in the contract's storage. + +This must be included in every contract because it depends on the storage slots, which are defined when we set up storage. + +#include_code compute_note_hash_and_nullifier /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +:::danger +If your contract works with storage (has Storage struct defined), you **MUST** include a `compute_note_hash_and_nullifier` function. +If you don't yet have any private state variables defined put there a placeholder function: + +#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust +::: + +## Compiling + +Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../sandbox/references/sandbox-reference.md) for instructions on setting it up. + +Run the following command in the directory where your `Nargo.toml` file is located: + +```bash +aztec-nargo compile +``` + +Once your contract is compiled, optionally generate a typescript interface with the following command: + +```bash +aztec-cli codegen target -o src/artifacts --ts +``` + +## Next Steps + +### Testing + +Review the end to end tests for reference: + +https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/end-to-end/src/e2e_token_contract.test.ts + +### Token Bridge Contract + +The [token bridge tutorial](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/token-bridge) 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. \ No newline at end of file diff --git a/docs/docs/developers/contracts/syntax/storage/private_state.md b/docs/docs/developers/contracts/references/storage/private_state.md similarity index 97% rename from docs/docs/developers/contracts/syntax/storage/private_state.md rename to docs/docs/developers/contracts/references/storage/private_state.md index c60590612c1..ccc81c20cd4 100644 --- a/docs/docs/developers/contracts/syntax/storage/private_state.md +++ b/docs/docs/developers/contracts/references/storage/private_state.md @@ -10,7 +10,7 @@ For a higher level overview of the state model in Aztec, see the [hybrid state m In contrast to public state, private state is persistent state that is **not** visible to the whole world. Depending on the logic of the smart contract, a private state variable's current value will only be known to one entity, or a closed group of entities. -The value of a private state variable can either be shared via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. +The value of a private state variable can either be shared via an [encrypted log](../../writing_contracts/events/emit_event.md#encrypted-events), or offchain via web2, or completely offline: it's up to the app developer. Aztec private state follows a [utxo](https://en.wikipedia.org/wiki/Unspent_transaction_output)-based model. That is, a private state's current value is represented as one or many [notes](#notes). Each note is stored as an individual leaf in a utxo-based merkle tree: the [private state tree](../../../../learn/concepts/storage/trees/main.md). @@ -184,7 +184,7 @@ Set is used for managing a collection of notes. All notes in a Set are of the sa You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/set.nr). -And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](../functions/calling_functions.md#public---private)). +And can be added to the `Storage` struct as follows. Here adding a set for a custom note, the TransparentNote (useful for [public -> private communication](../../writing_contracts/functions/call_functions.md)). #include_code storage-set-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -200,7 +200,7 @@ We can initialize the set as follows: Allows us to modify the storage by inserting a note into the set. -A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](../events.md#encrypted-events), or offchain via web2, or completely offline. +A hash of the note will be generated, and inserted into the note hash tree, allowing us to later use in contract interactions. Recall that the content of the note should be shared with the owner to allow them to use it, as mentioned this can be done via an [encrypted log](../../writing_contracts/events/emit_event.md#encrypted-events), or offchain via web2, or completely offline. #include_code insert /yarn-project/aztec-nr/easy-private-state/src/easy_private_state.nr rust @@ -248,7 +248,7 @@ This function requires a `NoteViewerOptions`. The `NoteViewerOptions` is essenti ## `NoteGetterOptions` -`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](../functions/oracles.md). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. +`NoteGetterOptions` encapsulates a set of configurable options for filtering and retrieving a selection of notes from a [data oracle](../../writing_contracts/oracles/main.md). Developers can design instances of `NoteGetterOptions`, to determine how notes should be filtered and returned to the functions of their smart contracts. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/note/note_getter_options.nr). diff --git a/docs/docs/developers/contracts/syntax/storage/public_state.md b/docs/docs/developers/contracts/references/storage/public_state.md similarity index 91% rename from docs/docs/developers/contracts/syntax/storage/public_state.md rename to docs/docs/developers/contracts/references/storage/public_state.md index 8c2a16bfe41..68eeb5bfdc1 100644 --- a/docs/docs/developers/contracts/syntax/storage/public_state.md +++ b/docs/docs/developers/contracts/references/storage/public_state.md @@ -8,7 +8,7 @@ For a higher level overview of the state model in Aztec, see the [state model](. ## Overview -The `PublicState` struct is generic over the variable type `T`. The type *must* implement Serialize and Deserialize traits, as specified here: +The `PublicState` struct is generic over the variable type `T`. The type _must_ implement Serialize and Deserialize traits, as specified here: #include_code serialize /yarn-project/noir-protocol-circuits/src/crates/types/src/traits.nr rust #include_code deserialize /yarn-project/noir-protocol-circuits/src/crates/types/src/traits.nr rust @@ -23,7 +23,7 @@ An example using a larger struct can be found in the [lending example](https://g ### `new` -When declaring the storage for `T` as a persistent public storage variable, we use the `PublicState::new()` constructor. As seen below, this takes the `storage_slot` and the [`Context`](../context.mdx), which in this case is used to share interface with other structures. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr). +When declaring the storage for `T` as a persistent public storage variable, we use the `PublicState::new()` constructor. As seen below, this takes the `storage_slot` and the `serialization_methods` as arguments along with the [`Context`](../../writing_contracts/functions/context.md), which in this case is used to share interface with other structures. You can view the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/public_state.nr). #### Single value example @@ -91,9 +91,9 @@ We have a `write` method on the `PublicState` struct that takes the value to wri ## Stable Public State -`StablePublicState` is a special type of `PublicState` that can be read from both public and private! +`StablePublicState` is a special type of `PublicState` that can be read from both public and private! -Since private execution is based on historical data, the user can pick ANY of its prior values to read from. This is why it `MUST` not be updated after the contract is deployed. The variable should be initialized at the constructor and then never changed. +Since private execution is based on historical data, the user can pick ANY of its prior values to read from. This is why it `MUST` not be updated after the contract is deployed. The variable should be initialized at the constructor and then never changed. This makes the stable public variables useful for stuff that you would usually have in `immutable` values in solidity. For example this can be the name of a token or its number of decimals. @@ -102,6 +102,7 @@ Just like the `PublicState` it is generic over the variable type `T`. The type ` You can find the details of `StablePublicState` in the implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr). ### `new` + Is done exactly like the `PublicState` struct, but with the `StablePublicState` struct. #include_code storage-stable-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -123,8 +124,8 @@ Currently this is not constrained as we are in the middle of changing deployment Reading the value is like `PublicState`, simply with `read_public` instead of `read`. #include_code read_decimals_public /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - ### `read_private` + Reading the value is like `PublicState`, simply with `read_private` instead of `read`. This part can only be executed in private. #include_code read_decimals_private /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust diff --git a/docs/docs/developers/contracts/resources/common_patterns/authwit.md b/docs/docs/developers/contracts/resources/common_patterns/authwit.md index 0858b4cbebb..40aed935b93 100644 --- a/docs/docs/developers/contracts/resources/common_patterns/authwit.md +++ b/docs/docs/developers/contracts/resources/common_patterns/authwit.md @@ -82,7 +82,7 @@ Both return the value `0xe86ab4ff` (`is_valid` selector) for a successful authen As part of [Aztec.nr](https://aztec.nr), we are providing a library that can be used to implement authentication witness for your contracts. -This library also provides a basis for account implementations such that these can more easily implement authentication witness. For more on the wallets, see [writing an account contract](./../../../wallets/writing_an_account_contract.md). +This library also provides a basis for account implementations such that these can more easily implement authentication witness. For more on the wallets, see [writing an account contract](../../writing_contracts/accounts/write_accounts_contract.md). For our purposes here (not building a wallet), the most important part of the library is the `auth` utility which exposes a couple of helper methods for computing the action hash, retrieving witnesses, validating them and emitting the nullifier. diff --git a/docs/docs/developers/contracts/resources/common_patterns/main.md b/docs/docs/developers/contracts/resources/common_patterns/main.md index 5d54f7b6e35..e19d9d14c76 100644 --- a/docs/docs/developers/contracts/resources/common_patterns/main.md +++ b/docs/docs/developers/contracts/resources/common_patterns/main.md @@ -95,7 +95,7 @@ This pattern is discussed in detail in [writing a token contract section in the When you send someone a note, the note hash gets added to the [note hash tree](../../../../learn/concepts/storage/trees/main.md#note-hash-tree). To spend the note, the receiver needs to get the note itself (the note hash preimage). There are two ways you can get a hold of your notes: -1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../../syntax/events.md) +1. When sending someone a note, use `emit_encrypted_log` (the function encrypts the log in such a way that only a recipient can decrypt it). PXE then tries to decrypt all the encrypted logs, and stores the successfully decrypted one. [More info here](../../writing_contracts/events/emit_event.md) 2. Manually using `pxe.addNote()` - If you choose to not emit logs to save gas or when creating a note in the public domain and want to consume it in private domain (`emit_encrypted_log` shouldn't be called in the public domain because everything is public), like in the previous section where we created a TransparentNote in public. #include_code pxe_add_note yarn-project/end-to-end/src/e2e_cheat_codes.test.ts typescript diff --git a/docs/docs/developers/contracts/setup.md b/docs/docs/developers/contracts/setup.md index 1779e4deb3d..482b7795383 100644 --- a/docs/docs/developers/contracts/setup.md +++ b/docs/docs/developers/contracts/setup.md @@ -1,5 +1,5 @@ --- -title: Setup +title: How to setup a new contract project --- import { AztecPackagesVersion } from "@site/src/components/Version"; @@ -85,5 +85,5 @@ You are now ready to write your own contracts! ## Next Steps -- Read up about how to [write a contract](./syntax/main.md) OR -- Follow a [tutorial](../tutorials/main.md) +- Follow a [tutorial](../tutorials/main.md) OR +- Read more diff --git a/docs/docs/developers/contracts/syntax/constrain.md b/docs/docs/developers/contracts/syntax/constrain.md deleted file mode 100644 index eb529c1e3b1..00000000000 --- a/docs/docs/developers/contracts/syntax/constrain.md +++ /dev/null @@ -1,2 +0,0 @@ -Not sure what this one's for? -`assert`? diff --git a/docs/docs/developers/contracts/syntax/control_structure.md b/docs/docs/developers/contracts/syntax/control_structure.md deleted file mode 100644 index d3d0e57a6cf..00000000000 --- a/docs/docs/developers/contracts/syntax/control_structure.md +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Control Structures ---- - -:::danger -Question: this feels like the wrong title for a section about how to call functions. 'Control structure' in my mind is "if/else", "for", "while". - -Can we not put "how to call functions" in the functions section? -::: - -# Function Calls - -## Private Function Calls - -## Public Function Calls - -## Private to Public Function Calls - -## Public to Private Function Calls diff --git a/docs/docs/developers/contracts/syntax/functions/calling_functions.md b/docs/docs/developers/contracts/syntax/functions/calling_functions.md deleted file mode 100644 index 4b24e32a9c2..00000000000 --- a/docs/docs/developers/contracts/syntax/functions/calling_functions.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Calling Functions from Other Functions ---- - -This page talks about how functions call other functions. For a more hands-on guide into calling functions from other functions, follow the [token tutorial](../../../tutorials/writing_token_contract.md). - -### Private -> Private - -In Aztec Private to Private function calls are handled by the [private kernel circuit](../../../../learn/concepts/circuits/kernels/private_kernel.md), and take place on the user's device. -Behind the scenes, the `Private Execution Environment (PXE)` (the beating heart of Aztec that runs in your wallet) will execute all of the functions in the desired order "simulating" them in sequence. For example, a very common use-case of private-to-private interaction is calling a private function on another contract from an `account contract` (Account contracts are a general concept, more information about them can be found [here](../../../wallets/writing_an_account_contract.md)). - -Take, for example, the following call stack: - -``` -AccountContract::entrypoint - |-> Foo::example_call - | -> Bar::nested_call - |-> Baz::example_call -``` - -In the example above the Account Contract has been instructed to call two external functions. In the first function all, to `Foo::example_call` a further nested call is performed to `Bar::nested_call`. Finally the Account Contract makes one last call to `Baz::example_call`. - -Lets further illustrate what these examples could look like - - - -```rust -// Foo contains a singular function that returns the result of Bar::nested_call -contract Foo { - #[aztec(private)] - fn example_call(input: Field) -> pub Field { - Bar::at().nested_call(input) - } -} - -// Bar contains a singular function that returns a `input + 1` -contract Bar { - #[aztec(private)] - fn nested_call(input: Field) -> pub Field { - input + 1 - } -} - -// Baz contains a singular function that simply returns `10` -contract Baz { - #[aztec(private)] - fn example_call() -> pub Field { - 10 - } -} -``` - -When simulating the following call stack, we can expect execution flow to continue procedurally. The simulator will begin at the account contract's entry point, find a call to `Foo::example_call`, then begin to execute the code there. When the simulator executes the code in contract `Foo`, it will find the further nested call to contract `Bar::nested_call`. It will execute the code in `Bar`, bringing the return value back to contract `Foo`. -The same process will be followed for contract `Baz`. - -So far the provided example is identical to other executions. Ethereum execution occurs in a similar way, during execution the EVM will execute instructions until it reaches an external call, where it will hop into a new context and execute code there, returning back when it is complete, bringing with it return values from the foreign execution. - -Aztec differs from Ethereum in that these function calls are really executing zk programs (or circuits). The account contract, contract `Foo`, `Bar` and `Baz` are all distinct circuits, which are not directly aware of one another in the way that Ethereum contracts are. How is it possible to use a value from contract `Bar` in contract `Foo`? `Foo` cannot guarantee claims about the execution of `Bar`. - -This is where the `kernel` circuit comes in. Once the execution of all of the contract functions has completed, it can prove the execution of each of them independently. It is the job of the `kernel` circuit to constrain that the input parameters in a cross function call are correct, as well as the return values. The kernel will constrain that the value returned from `Foo::example_call` is the same value that is returned from `Bar::nested_call`, it will also be able to guarantee the value returned by `Bar::nested_call` is the inputs to `Foo::example_call` + 1. - -The orchestration of these calls has an added benefit. All of the nested calls are **recursively proven**. This means that the kernel circuit essentially aggregates each of our function's execution proofs, resulting in one proof that proves all function execution. - - - -With this intuition in place, lets see how we actually perform the call. To make things easier, we can make a small struct that wraps the calls to something as seen in the token interface `burn` function below. This struct is providing us a clean way to call function, but we could also just call the function directly as it is done in this function. - -:::info -Note that the function selector is computed using Oracles, and that the first `Field` is wrapped in parenthesis. Structs are outlined in tuple-form for selector computation, so they are wrapped in parenthesis--e.g. `AztecAddress` becomes `(Field)`. -::: - -#include_code private_burn_interface /yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr rust - -Using this interface, we can then call it as seen below. All the way down at the bottom we can see that we are calling the `burn` function from the `token_interface` struct. - -The following snippet is from a token bridge that is burning the underlying token and creating a message for L1 to mint some assets to the `recipient` on Ethereum. - -#include_code exit_to_l1_private /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust - -### Public -> Public - -The public execution environment in Aztec takes place on the sequencer through a [Public VM](../../../../learn/concepts/hybrid_state/public_vm.md). This execution model is conceptually much simpler than the private transaction model as code is executed and proven on the sequencer. - -Using the same example code and call stack from the section [above](#private---private-function-calls), we will walk through how it gets executed in public. - -The first key difference is that public functions are not compiled to circuits, rather they are compiled to `Aztec Bytecode`. - -This bytecode is run by the sequencer in the `Aztec VM`, which is in turn proven by the [`Aztec VM circuit`](../../../../learn/concepts/hybrid_state/public_vm.md). -The mental model for public execution carries many of the same idea as are carried by Ethereum. Programs are compiled into a series of opcodes (known as bytecode). This bytecode is then executed. The extra step for the Aztec VM is that each opcode is then proven for correctness. - -Calling a public function from another public function is quite similar to what we saw for private to private, with the keyword private swapped for public. - -#include_code public_burn_interface /yarn-project/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr rust -#include_code exit_to_l1_public /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust - -### Private -> Public - -As discussed above, private function execution and calls take place on the user's device, while public function execution and calls take place on a sequencer, in two different places at two different times. We can achieve composability between the two contexts via asynchronicity. Further reading can be found in the concepts [here](../../../../learn/concepts/communication/public_private_calls/main.md). - -Private function execution takes place on the users device, where it keeps track of any public function calls that have been made. Whenever private execution completes, and a kernel proof is produced, the transaction sent to the network will include all of the public calls that were dispatched. -When the sequencer receives the messages, it will execute the public parts of the transaction. - -As a consequence a private function _CANNOT_ accept a return value from a public function. It can only dispatch it. - -The code required to dispatch a public function call from a private function is similar to private-to-private calls. As an example, we will look at the token contract, where users can unshield assets from private to public domain. This is essentially a transfer from a private account to a public one (often used for depositing privately into DeFi etc). - -#include_code unshield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust -#include_code increase_public_balance /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -As we can see above, in the code the private to public transaction flow looks very similar to the others in snippets, with the transaction data flow being a bit different behind the scenes. - - - -### Public -> Private - - -While we cannot directly call a private function from a public function, we can indirectly call it by adding a commitment to the note hash tree. This commitment can then be consumed by a private function later, to "finish" the execution. So while it is not practically a call, we can ensure that it could only happen as an effect of a public function call, which is still useful. - -In the snippet below, we insert a custom note, the transparent note, into the commitments tree from public such that it can later be consumed in private. - -#include_code shield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -If you recall the `redeem_shield` from back in the [private function section](./public_private_unconstrained.md#private-functions), you might remember it removing a `TransparentNote` from `pending_shields`. This is the note that we just inserted from public! - -#include_code redeem_shield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -When the note is removed, it emits a nullifier so that it cannot be used again. This nullifier is then added to the nullifier tree, and can be used to prove that the note was removed from the pending shields. Interestingly, we can generate the nullifier such that no-one who saw the public execution will know that it have been consumed. When sending messages between L1 and L2 in [portals](./../../../../learn/concepts/communication/cross_chain_calls.md) we are going to see this pattern again. - -:::danger -Something to be mindful of when inserting from public. Everyone can see the insertion and what happens in public, so if you are including a secret directly anyone would be able to see it. This is why the hash of the secret is used in the snippet above (`secret_hash`). -::: - diff --git a/docs/docs/developers/contracts/syntax/functions/constructor.md b/docs/docs/developers/contracts/syntax/functions/constructor.md deleted file mode 100644 index d0a9c7d0c3b..00000000000 --- a/docs/docs/developers/contracts/syntax/functions/constructor.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: Constructor ---- -This page talks about declaring constructors in functions. - -For a more hands-on guide into declaring a constructor, follow the [private voting tutorial](../../../tutorials/writing_private_voting_contract.md). - -A special `constructor` function **must** be declared within a contract's scope. -- A constructor doesn't have a name, because its purpose is clear: to initialize contract state. -- In Aztec terminology, a constructor is always a '`private` function' (i.e. it cannot be a `public` function). -- A constructor behaves almost identically to any other function. It is just important for Aztec to be able to identify this function as special: it may only be called once, and will not be deployed as part of the contract. - -Although you can have a constructor that does nothing, you might want to do something with it, such as setting the deployer as an owner. - -#include_code constructor /yarn-project/noir-contracts/contracts/escrow_contract/src/main.nr rust diff --git a/docs/docs/developers/contracts/syntax/main.md b/docs/docs/developers/contracts/syntax/main.md deleted file mode 100644 index 73a6c7ffddc..00000000000 --- a/docs/docs/developers/contracts/syntax/main.md +++ /dev/null @@ -1,22 +0,0 @@ -import DocCardList from '@theme/DocCardList'; -import { AztecPackagesVersion } from "@site/src/components/Version"; - -# Aztec.nr Syntax - -[Noir](https://noir-lang.org/) is a language which is agnostic to proof systems and use cases. Rather than baking Aztec-specific keywords and smart contract types directly into Noir (which would break this agnosticism), we have developed a framework -- written in Noir -- whose types and methods provide rich smart contract semantics. - -On top of [Noir's stdlib](https://noir-lang.org/docs/noir/standard_library/cryptographic_primitives), we provide [Aztec.nr](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec-nr) for writing contracts on Aztec. - -Aztec.nr contains abstractions which remove the need to understand the low-level Aztec protocol. Notably, it provides: - -- Public and private [state variable types](./storage/main.md) -- Some pre-designed notes -- Functions for [emitting](./events.md) encrypted and unencrypted logs -- [Oracle functions](./functions/oracles.md) for accessing: - - private state - - secrets -- Functions for communicating with [Ethereum L1](../portals/main.md) - -To setup a aztec-nr project, follow the [setup instructions](../setup.md) - - diff --git a/docs/docs/developers/contracts/syntax/slow_updates_tree.md b/docs/docs/developers/contracts/syntax/slow_updates_tree.md deleted file mode 100644 index 4f1e79608a1..00000000000 --- a/docs/docs/developers/contracts/syntax/slow_updates_tree.md +++ /dev/null @@ -1,264 +0,0 @@ ---- -title: Slow Updates Tree ---- - -Slow Updates Tree is a data structure that allows for historical public data to be accessed in both private and public domains. Read the high level overview in the [Communication section](../../../learn/concepts/communication/public_private_calls/slow_updates_tree.md). - -The slow updates tree works by having a current tree and a pending tree, and replacing the current tree with the pending tree after an epoch has passed. Public functions can read directly from the current tree, and private functions can perform a membership proof that values are part of a commitment to the current state of the tree. - -On this page you will learn: - -1. [The components involved in using the slow updates tree](slow_updates_tree.md#components-involved-in-implementing-a-slow-updates-tree) -2. [How you can integrate it into your own smart contract](slow_updates_tree.md#how-to-integrate-a-slow-updates-tree) -3. [An example of a token blacklisting contract that uses the slow updates tree](slow_updates_tree.md#exploring-an-example-integration-through-a-tokenblacklist-smart-contract) -4. [Interface Reference](slow_updates_tree.md#reference) - -# Components involved in implementing a slow updates tree - -There are generally 4 main components involved to make it easier to use a slow updates tree, with 3 already implemented by Aztec. This makes it easier to interact with a slow updates tree through a simple interface. These four components are: - -## Main smart contract - -This is the primary smart contract that will use the slow updates tree. In the example we use a [token with blacklisting features](slow_updates_tree.md#exploring-an-example-integration-through-a-tokenblacklist-smart-contract). - -## Interface - -This interface of the slow updates tree contract allows your contract to interact with the Slow Updates Tree contract. It provides methods for reading and updating values in the tree in both public and private contexts. You can find it [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr). - -## SlowTree.nr contract - -This is a smart contract developed by Aztec that establishes and manages a slow updates tree structure. It allows developers to access and interact with the tree, such as reading and updating data. - -You can find it [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/slow_tree_contract). - -## SlowMap type - -This is a type in the Aztec.nr library that is utilized by the SlowTree contract. It defines the underlying data structure for the slow updates tree, and handles storing both the current and pending values for each data entry. - -You can find it [here](https://github.com/AztecProtocol/aztec-nr/blob/master/slow-updates-tree/src/slow_map.nr). - -The diagram below describes how these components work together. It does not contain all the functionality. - -```mermaid -graph TD - MSC[Main Smart Contract] --> INT[Interface] - STC --> SMT - - INT_RAP[read_at_pub] <--> STC_RAP[read_at_public] - INT_RA[read_at] <--> STC_RA[read_at] - INT_UAP[update_at_public] <--> STC_UAP[update_at_public] - INT_UA[update_at_private] <--> STC_UA[update_at_private] - - STC_RA <--> VMP[verify_membership_proof] - STC_UA <--> CR[compute_roots] - - subgraph INT[Interface] - INT_RAP - INT_UAP - INT_RA - INT_UA - end - - subgraph STC[SlowTree.nr] - STC_RAP - STC_UAP - STC_RA - STC_UA - end - - subgraph SMT[SlowMap Type] - Change{Epoch Over} -->|True| Current{Current} - Change -->|False| Pending{Pending} - Current --> Current1[Current Commitment 1] - Current --> CurrentM[Current Commitment M] - CurrentM --> Value1[Current Value 1] - CurrentM --> Value2[Current Value 2] - CurrentM --> ValueN[Current Value N] - Pending --> PendingM[Pending Commitment 1] - PendingM --> PValue1[Pending Value 1] - PendingM --> PValue2[Pending Value 2] - PendingM --> PValueN[Pending Value N] - end - - style INT fill:#fff,stroke:#333,stroke-width:1px - style STC fill:#fff,stroke:#333,stroke-width:1px - style SMT fill:#fff,stroke:#333,stroke-width:1px -``` - -# How to integrate a slow updates tree - -1. Copy the *SlowTree.nr* example and its dependencies, found [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/slow_tree_contract). Replace the constants with whatever you like and deploy it to your sandbox -2. Copy the *SlowMap interface* for easy interaction with your deployed SlowTree. Find it [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr) -3. Import this interface into your contract - -#include_code interface yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -5. Store the SlowTree address in private storage as a FieldNote - -#include_code constructor yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -6. Store the SlowTree address in public storage and initialize an instance of SlowMap using this address - -#include_code write_slow_update_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -7. Now you can read and update from private functions: - -#include_code get_and_update_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -8. Or from public functions: - -#include_code get_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -View the [reference](slow_updates_tree.md#reference) for more information. - -## Exploring an example integration through a **`TokenBlacklist`** Smart Contract - -The `TokenBlacklist` contract is a token contract that does not allow blacklisted accounts to perform mints or transfers. In this section we will go through how this is achieved through the slow updates tree. - -You can find the full code for the TokenBlacklist smart contract [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/token_blacklist_contract). - -### Importing SlowMap - -The contract first imports the **`SlowMap`** interface: - -#include_code interface yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -This interface allows the contract to interact with its attached SlowTree. It abstracts these functions so they do not have to be implemented in the TokenBlacklist contract. - -### Constructor and initialization - -The contract's constructor takes the address of the slow updates contract: - -#include_code constructor yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -This initialization sets up the connection between the **`TokenBlacklist`** contract and a previously deployed SlowTree, allowing it to use the interface to directly interact with the SlowTree. - -### Private transfer function utilizing the slow updates tree - -In the private transfer function, the contract uses the interface to check if a user is blacklisted: - -#include_code transfer_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -Here, the contract reads the roles of the sender and recipient from the SlowTree using the **`read_at`** function in the interface. It checks if either party is blacklisted, and if so, the transaction does not go ahead. - -# Reference - -## Struct `SlowMap` - -### Overview -The `SlowMap` struct is used to interact with a slow updates tree deployed via the SlowTree smart contract. - -### Fields - -| Name | Type | Description | -|---------|-----------|---------------------------------| -| address | `Field` | The address of the SlowTree contract | - -## Functions - -### at - -Returns an instance of `SlowMap` at the specified address. - -**Parameters** - -| Name | Type | Description | -|----------|----------------|----------------------------| -| `address`| `AztecAddress` | The address of the SlowTree | - -**Return** - -| Name | Type | Description | -|-------|-----------|------------------------------| -| - | `SlowMap` | The `SlowMap` instance | - -**Example** - -#include_code slowmap_at yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -### initialize - -Initializes the `SlowMap`. - -**Parameters** - -| Name | Type | Description | -|-----------|-----------------|----------------------| -| `context` | `PublicContext` | The execution context | - -**Return** - -| Name | Type | Description | -|------|------|-------------| -| - | - | - | - -**Example** - -#include_code slowmap_initialize yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -### read_at_pub - -Reads a value at a specified index from a public function. - -**Parameters** - -| Name | Type | Description | -|-----------|-----------------|-----------------------| -| `context` | `PublicContext` | The execution context | -| `index` | `Field` | The index to read at | - -**Return** - -| Name | Type | Description | -|----------|--------|-----------------------| -| `result` | `Field`| The value at `index` | - -**Example** - -#include_code read_at_pub yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -### read_at - -Reads a value at a specified index from a private function. - -**Parameters** - -| Name | Type | Description | -|-----------|--------------------|------------------------| -| `context` | `PrivateContext` | The execution context | -| `index` | `Field` | The index to read at | - -**Return** - -| Name | Type | Description | -|----------|--------|-----------------------| -| `result` | `Field`| The value at `index` | - -**Example** - -#include_code slowmap_read_at yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -### update_at_private - -Updates a value at a specified index from a private function. Does not return anything. - -**Parameters** - -| Name | Type | Description | -|-------------|--------------------|------------------------| -| `context` | `PrivateContext` | The execution context | -| `index` | `Field` | The index to update | -| `new_value` | `Field` | The new value | - -**Example** - -#include_code get_and_update_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - -## Updating from public - -This is not a method in the interface as it can be done using regular Aztec.nr public storage update syntax. - -**Example** - -#include_code write_slow_update_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust - diff --git a/docs/docs/developers/contracts/syntax/storage/main.md b/docs/docs/developers/contracts/syntax/storage/main.md deleted file mode 100644 index 1d233536235..00000000000 --- a/docs/docs/developers/contracts/syntax/storage/main.md +++ /dev/null @@ -1,133 +0,0 @@ ---- -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. - -You control this storage in Aztec using the `Storage` struct. 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. - -These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. - -Aztec.nr has a few abstractions to help define the type of data your contract holds. These include Singletons, ImmutableSingletons, Set, and Map. - -On this and the following pages in this section, you’ll learn: - -- How to manage a smart contract's storage structure -- The distinctions and applications of public and private state variables -- How to use Singleton, ImmutableSingleton, Set, and Map -- An overview of 'notes' and the UTXO model -- Practical implications of Storage in real smart contracts - In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. - -## Public and private state variables - -Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). - -Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (pre-images) are only known by the sender and those able to decrypt them - see ([state model](../../../../learn/concepts/hybrid_state/main.md) and [private/public execution](../../../../learn/concepts/communication/public_private_calls/main.md)) for more background. - -## Storage struct - -:::info -The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). -::: - -```rust -struct Storage { - // public state variables - // private state variables -} -``` - -:::danger -If your contract uses storage (has Storage struct defined), you **MUST** include a `compute_note_hash_and_nullifier` function to allow PXE to process encrypted events. See [encrypted events](../events.md#processing-encrypted-events) for more. - -If you don't yet have any private state variables defined you can use this placeholder function: - -#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust -::: - -Since Aztec.nr is written in Noir, which is state-less, we need to specify how the storage struct should be initialized to read and write data correctly. In most cases, the initialization of the storage is handled by the Aztec.nr library, which creates a default implementation based on the provided `Storage` struct. - -:::danger -The automatic initialization has some limitations. Using any combination of the provided storage primitives (`PublicState`, `Singleton`, `ImmutableSingleton`, `Set`, `Map`, including nested ones) will ensure that the library will be able to handle it on its own. - -Custom structures are also supported as long as they are generic over `T`, where `T` implements `Serialize` and `Deserialize` in the case it represents public state and additionally `NoteInterface` for private state. -::: - -Custom initialization of the storage is also possible. This is done by specifying an `init` function that is run in functions that rely on reading or altering the state variables. This `init` function must declare the Storage struct with an instantiation defining how variables are accessed and manipulated. The function MUST be called `init` for the Aztec.nr library to properly handle it (this will be relaxed in the future). - -```rust -impl Storage { - fn init(context: Context) -> Self { - Storage { - // (public state variables)::new() - // (private state variables)::new() - } - } -} -``` - -If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions. - -:::warning Using slot `0` is not supported! -No storage values should be initialized at slot `0` - storage slots begin at `1`. This is a known issue that will be fixed in the future. -::: - -## Map - -A `map` is a state variable that "maps" a key to a value. It can be used with private or public storage variables. - -:::info -In Aztec.nr, keys are always `Field`s, or types that can be serialized as Fields, and values can be any type - even other maps. `Field`s are finite field elements, but you can think of them as integers. -::: - -It includes a [`Context`](../context.mdx) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. - -You can view the implementation in the Aztec.nr library [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec-nr/aztec/src/state_vars/map.nr). - -### `new` - -When declaring the storage for a map, we use the `Map::new()` constructor. This takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](../context.mdx). - -We will see examples of map constructors for public and private variables in later sections. - -#### As private storage - -When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `Singleton` note type. - -In the Storage struct: - -#include_code storage-map-singleton-declaration /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -#### Public Example - -When declaring a public mapping in Storage, we have to specify that the type is public by declaring it as `PublicState` instead of specifying a note type like with private storage above. - -In the Storage struct: - -#include_code storage_minters /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -### `at` - -When dealing with a Map, we can access the value at a given key using the `::at` method. This takes the key as an argument and returns the value at that key. - -This function behaves similarly for both private and public maps. An example could be if we have a map with `minters`, which is mapping addresses to a flag for whether they are allowed to mint tokens or not. - -#include_code read_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust - -Above, we are specifying that we want to get the storage in the Map `at` the `msg_sender()`, read the value stored and check that `msg_sender()` is indeed a minter. Doing a similar operation in Solidity code would look like: - -```solidity -require(minters[msg.sender], "caller is not minter"); -``` - -## Further Reading - -- Managing [Public State](./public_state.md) -- Jump to the page on [Private State](./private_state.md) - -## Concepts mentioned - -- [Hybrid State Model](../../../../learn/concepts/hybrid_state/main.md) -- [Public-private execution](../../../../learn/concepts/communication/public_private_calls/main.md) -- [Function Contexts](../context.mdx) diff --git a/docs/docs/developers/contracts/testing_contracts/main.md b/docs/docs/developers/contracts/testing_contracts/main.md new file mode 100644 index 00000000000..39f54296b0a --- /dev/null +++ b/docs/docs/developers/contracts/testing_contracts/main.md @@ -0,0 +1,9 @@ +--- +title: Testing Contracts +--- + +We are currently working on a Foundry-like tool for writing unit tests in Noir. + +For now, it is easier to write e2e tests using [Aztec.js](../../aztecjs/main.md). + +To make testing easier, the sandbox is shipped with cheat codes to easily test in different states. Read about them and find a list [here](../../sandbox/references/cheat_codes.md). \ No newline at end of file diff --git a/docs/docs/developers/contracts/workflow.md b/docs/docs/developers/contracts/workflow.md deleted file mode 100644 index bfce487749d..00000000000 --- a/docs/docs/developers/contracts/workflow.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -title: Contract Workflow ---- - -## Setup -[Set up your project](./setup.md) - -## Write - -[Write a contract](./syntax/main.md). - -## Compile - -[Compile a contract](./compiling.md). - -## Unit Tests - -[Test individual noir functions](https://noir-lang.org/docs/getting_started/tooling/testing). - -## Deploy - -[Deploy a contract](./deploying.md). - -## Integration Tests - -[Test a deployed contract](../testing/main.md) diff --git a/docs/docs/developers/wallets/writing_an_account_contract.md b/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md similarity index 77% rename from docs/docs/developers/wallets/writing_an_account_contract.md rename to docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md index fdc46499755..ec559fa2546 100644 --- a/docs/docs/developers/wallets/writing_an_account_contract.md +++ b/docs/docs/developers/contracts/writing_contracts/accounts/write_accounts_contract.md @@ -1,34 +1,36 @@ -# Writing an Account Contract +--- +title: How to write an accounts contract +--- -This tutorial will take you through the process of writing your own account contract in Noir, along with the Typescript glue code required for using it within a [wallet](./main.md). +This tutorial will take you through the process of writing your own account contract in Aztec.nr, along with the Typescript glue code required for using it within a wallet. You will learn: - How to write a custom account contract in Aztec.nr - The entrypoint function for transaction authentication and call execution - The AccountActions module and EntrypointPayload struct, necessary inclusions for any account contract -- Customizing authorization validation within the 'is_valid' function (using Schnorr signatures as an example) +- Customizing authorization validation within the `is_valid` function (using Schnorr signatures as an example) - Typescript glue code to format and authenticate transactions - Deploying and testing the account contract -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](../../learn/concepts/accounts/main.md#what-is-account-abstraction) in the Aztec network. +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](../../../../learn/concepts/accounts/main.md#what-is-account-abstraction) in the Aztec network. -It is highly recommended that you understand how an [account](../../learn/concepts/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../learn/concepts/accounts/keys.md). You will also need to know how to write a [contract in Noir](../contracts/main.md), as well as some basic [Typescript](https://www.typescriptlang.org/). +It is highly recommended that you understand how an [account](../../../../learn/concepts/accounts/main.md) is defined in Aztec, as well as the differences between privacy and authentication [keys](../../../../learn/concepts/accounts/keys.md). You will also need to know how to write a [contract in Noir](../layout.md), 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. -> That is, every time a transaction payload is passed to this account contract's 'entrypoint' function, the account contract will demand 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. +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](../../learn/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](../../learn/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../learn/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](../../../../learn/concepts/accounts/keys.md#using-a-private-note), [in an immutable note](../../../../learn/concepts/accounts/keys.md#using-an-immutable-private-note), or [on a separate keystore](../../../../learn/concepts/accounts/keys.md#using-a-separate-keystore), to mention a few examples. ## The account contract -Let's start with the account contract itself in Aztec.nr. Create [a new Aztec.nr contract project](../contracts/main.md) that will contain a file with the code for the account contract, with a hardcoded public key: +Let's start with the account contract itself in Aztec.nr. Create [a new Aztec.nr contract project](../../main.md) that will contain a file with the code for the account contract, with a hardcoded public key: #include_code contract yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr rust :::info -You can use [the Aztec CLI](../cli/main.md) to generate a new keypair if you want to use a different one: +You can use [the Aztec CLI](../../../sandbox/main.md) to generate a new keypair if you want to use a different one: ```bash $ aztec-cli generate-private-key @@ -83,11 +85,11 @@ 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](../../learn/concepts/accounts/keys.md#privacy-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](../../../../learn/concepts/accounts/keys.md#privacy-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 -Note that we get a [`Wallet` instance](./main.md) out of the account, which we can use for initializing the token contract class after deployment, so any transactions sent to it are sent from our wallet. We can then send a transaction to it and check its effects: +Note that we get a [`Wallet` instance](../../../../learn/concepts/accounts/main.md#account-contracts-and-wallets) out of the account, which we can use for initializing the token contract class after deployment, so any transactions sent to it are sent from our wallet. We can then send a transaction to it and check its effects: #include_code account-contract-works yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript @@ -98,3 +100,5 @@ To make sure that we are actually validating the provided signature in our accou #include_code account-contract-fails yarn-project/end-to-end/src/guides/writing_an_account_contract.test.ts typescript Lo and behold, we get `Error: Assertion failed: 'verification == true'` when running the snippet above, pointing to the line in our account contract where we verify the Schnorr signature. + + diff --git a/docs/docs/developers/contracts/syntax/events.md b/docs/docs/developers/contracts/writing_contracts/events/emit_event.md similarity index 90% rename from docs/docs/developers/contracts/syntax/events.md rename to docs/docs/developers/contracts/writing_contracts/events/emit_event.md index 234e978544f..f0631f076e9 100644 --- a/docs/docs/developers/contracts/syntax/events.md +++ b/docs/docs/developers/contracts/writing_contracts/events/emit_event.md @@ -1,5 +1,5 @@ --- -title: Events +title: How to emit an event --- Events in Aztec work similarly to Ethereum events in the sense that they are a way for contracts to communicate with the outside world. @@ -10,10 +10,12 @@ Aztec events are currently represented as raw data and are not ABI encoded. ABI encoded events are a feature that will be added in the future. ::: -Unlike on Ethereum, there are 2 types of events supported by Aztec: encrypted and unencrypted. +Unlike on Ethereum, there are 2 types of events supported by Aztec: [encrypted](#encrypted-events) and [unencrypted](#unencrypted-events). ## Encrypted Events +### Register a recipient + Encrypted events can only be emitted by private functions and are encrypted using a public key of a recipient. For this reason it is necessary to register a recipient in the Private Execution Environment (PXE) before encrypting the events for them. Recipients can be registered using the Aztec CLI or Aztec.js: @@ -54,22 +56,26 @@ await pxe.registerRecipient(completeAddress); :::info -If a note recipient is one of the accounts inside the PXE, we don't need to register it as a recipient because we already have the public key available. You can register a recipient as shown [here](../deploying#deploying-private-token-contract) +If a note recipient is one of the accounts inside the PXE, we don't need to register it as a recipient because we already have the public key available. You can register a recipient as shown [here](../../deploying_contracts/how_to_deploy_contract.md) At this point the Sandbox only enables the emitting of encrypted note preimages through encrypted events. In the future we will allow emitting arbitrary information. (If you currently emit arbitrary information, PXE will fail to decrypt, process and store this data, so it will not be queryable). ::: -To emit encrypted logs first import the `emit_encrypted_log` utility function which wraps an [oracle](./functions/oracles.md): +### Import library + +To emit encrypted logs first import the `emit_encrypted_log` utility function which wraps an [oracle](../oracles/main.md): #include_code encrypted_import /yarn-project/aztec-nr/address-note/src/address_note.nr rust -Then you can call the function: +### Call emit_encrypted_log + +After importing, you can call the function: #include_code encrypted /yarn-project/aztec-nr/address-note/src/address_note.nr rust -### Processing Encrypted Events +### Successfully process the encrypted event One of the functions of the PXE is constantly loading encrypted logs from the `AztecNode` and decrypting them. When new encrypted logs are obtained, the PXE will try to decrypt them using the private encryption key of all the accounts registered inside PXE. @@ -95,17 +101,23 @@ They can be emitted by both public and private functions. :::danger - Emitting unencrypted events from private function is a significant privacy leak and it should be considered by the developer whether it is acceptable. -- Unencrypted events are currently **NOT** linked to the contract emitting them, so it is practically a [`debug_log`](./functions/oracles.md#a-few-useful-inbuilt-oracles). +- Unencrypted events are currently **NOT** linked to the contract emitting them, so it is practically a [`debug_log`](../oracles/main.md#a-few-useful-inbuilt-oracles). ::: +### Import library + To emit unencrypted logs first import the `emit_unencrypted_log` utility function inside your contract: #include_code unencrypted_import /yarn-project/noir-contracts/contracts/test_contract/src/main.nr rust -Then you can call the function: +### Call emit_unencrypted_log + +After importing, you can call the function: #include_code emit_unencrypted /yarn-project/noir-contracts/contracts/test_contract/src/main.nr rust +### Querying the unencrypted event + Once emitted, unencrypted events are stored in AztecNode and can be queried by anyone: diff --git a/docs/docs/developers/contracts/example-contract.md b/docs/docs/developers/contracts/writing_contracts/example_contract.md similarity index 94% rename from docs/docs/developers/contracts/example-contract.md rename to docs/docs/developers/contracts/writing_contracts/example_contract.md index 58eb023c5c7..692c8c21b97 100644 --- a/docs/docs/developers/contracts/example-contract.md +++ b/docs/docs/developers/contracts/writing_contracts/example_contract.md @@ -1,5 +1,5 @@ --- -title: Example Aztec.nr Contract +title: What a contract looks like --- ## Example Aztec.nr Contract diff --git a/docs/docs/developers/contracts/writing_contracts/functions/call_functions.md b/docs/docs/developers/contracts/writing_contracts/functions/call_functions.md new file mode 100644 index 00000000000..b1f40b09310 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/functions/call_functions.md @@ -0,0 +1,38 @@ +--- +title: How to call functions from other functions +--- + +A contract is a collection of persistent [state variables](../../references/storage/main.md), and [functions](../functions/main.md) 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. + +# Contract + +A contract may be declared and given a name using the `contract` keyword (see snippet below). By convention, contracts are named in `PascalCase`. + +```rust title="contract keyword" +// highlight-next-line +contract MyContract { + + // Imports + + // Storage + + // Functions +} +``` +:::info A note for vanilla Noir devs +There is no [`main()`](https://noir-lang.org/docs/getting_started/project_breakdown/#mainnr) function within a Noir `contract` scope. More than one function can be an entrypoint. +::: + +## Directory structure + +Here's a common layout for a basic Aztec.nr Contract project: + +```title="layout of an aztec contract project" +─── my_aztec_contract_project + ├── src + │ ├── main.nr <-- your contract + └── Nargo.toml <-- package and dependency management +``` + +- 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 token contract tutorial [here](.././../../tutorials/writing_token_contract.md). diff --git a/docs/docs/developers/contracts/syntax/context.mdx b/docs/docs/developers/contracts/writing_contracts/functions/context.md similarity index 85% rename from docs/docs/developers/contracts/syntax/context.mdx rename to docs/docs/developers/contracts/writing_contracts/functions/context.md index 5f6a028dfed..a9b5609cff0 100644 --- a/docs/docs/developers/contracts/syntax/context.mdx +++ b/docs/docs/developers/contracts/writing_contracts/functions/context.md @@ -1,16 +1,12 @@ --- title: Function Context -description: Documentation of Aztec's Private and Public execution contexts -hide_table_of_contents: false --- -import Image from "@theme/IdealImage"; - # The Function 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](../../../learn/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 it's 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](../../../../learn/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 it's 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 an developer's eyes; the context is a useful structure that allows access and mutate the state of the `Aztec` blockchain. @@ -22,8 +18,9 @@ On this page, you'll learn - Elements like return values, read requests, new commitments, and nullifiers in transaction processing - Differences between the private and public contexts, especially the unique features and variables in the public context -## Two context's one API -The `Aztec` blockchain contains two environments [public and private](../../../learn/concepts/hybrid_state/main.md). +## Two contexts, one API +The `Aztec` blockchain contains two environments [public and private](../../../../learn/concepts/hybrid_state/main.md). + - Private, for private transactions taking place on user's devices. - Public, for public transactions taking place on the network's sequencers. @@ -34,7 +31,7 @@ The following section will cover both contexts. ## The Private Context The code snippet below shows what is contained within the private context. -#include_code private-context /yarn-project/aztec-nr/aztec/src/context.nr rust +#include_code private-context /yarn-project/aztec-nr/aztec/src/context/private_context.nr rust ### Private Context Broken Down @@ -42,7 +39,7 @@ The code snippet below shows what is contained within the private context. The context inputs includes all of the information that is passed from the kernel circuit into the application circuit. It contains the following values. -#include_code private-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code private-context-inputs /yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr rust As shown in the snippet, the application context is made up of 4 main structures. The call context, the block header, the contract deployment data and the private global variables. @@ -57,14 +54,14 @@ The call context contains information about the current call being made: > The graphic below illustrates how the message sender changes throughout the kernel circuit iterations. - + 2. Storage contract address - This value is the address of the current context's contract address. This value will be the value of the current contract that is being executed except for when the current call is a delegate call (Warning: This is yet to be implemented). In this case the value will be that of the sending contract. 3. Portal Contract Address - - This value stores the current contract's linked [portal contract](../portals/main.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. + - This value stores the current contract's linked [portal contract](../portals/portals.md) address. As a quick recap, this value is the value of the contracts related ethereum l1 contract address, and will be the recipient of any messages that are created by this contract. 4. Flags - Furthermore there are a series of flags that are stored within the application context: - is_delegate_call: Denotes whether the current call is a delegate call. If true, then the storage contract address will be the address of the sender. @@ -89,7 +86,7 @@ Just like with the `is_contract_deployment` flag mentioned earlier. This data wi In the private execution context, we only have access to a subset of the total global variables, we are restricted to those which can be reliably proven by the kernel circuits. -#include_code private-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code private-global-variables /yarn-project/aztec-nr/aztec/src/context/globals/private_global_variables.nr rust ### Args Hash @@ -99,7 +96,7 @@ The `args_hash` is the result of pedersen hashing all of a function's inputs. ### Return Values -The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](./functions/inner_workings.md#after-expansion) for more details. +The return values are a set of values that are returned from an applications execution to be passed to other functions through the kernel. Developers do not need to worry about passing their function return values to the `context` directly as `Aztec.nr` takes care of it for you. See the documentation surrounding `Aztec.nr` [macro expansion](./inner_workings.md#after-expansion) for more details. return_values : BoundedVec, @@ -131,7 +128,7 @@ The public call stack contains all of the external function calls that are creat ### New L2 to L1 msgs -New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../learn/concepts/communication/cross_chain_calls.md) on the execution of each rollup. +New L2 to L1 messages contains messages that are delivered to the [l1 outbox](../../../../learn/concepts/communication/cross_chain_calls.md) on the execution of each rollup. ## Public Context @@ -141,10 +138,10 @@ The Public Context includes all of the information passed from the `Public VM` i In the current version of the system, the public context is almost a clone of the private execution context. It contains the same call context data, access to the same historical tree roots, however it does NOT have access to contract deployment data, this is due to traditional contract deployments only currently being possible from private transactions. -#include_code public-context-inputs /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code public-context-inputs /yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr rust ### Public Global Variables The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables. -#include_code public-global-variables /yarn-project/aztec-nr/aztec/src/abi.nr rust +#include_code global-variables /yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr rust diff --git a/docs/docs/developers/contracts/syntax/functions/inner_workings.md b/docs/docs/developers/contracts/writing_contracts/functions/inner_workings.md similarity index 88% rename from docs/docs/developers/contracts/syntax/functions/inner_workings.md rename to docs/docs/developers/contracts/writing_contracts/functions/inner_workings.md index 3b1a093e00a..47f2316d2f5 100644 --- a/docs/docs/developers/contracts/syntax/functions/inner_workings.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/inner_workings.md @@ -54,7 +54,7 @@ Inside the kernel circuits, the inputs to functions are reduced to a single valu **Creating the function's context.** #include_code context-example-context /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust -Each Aztec function has access to a [context](../context.mdx) object. This object, although labelled a global variable, is created locally on a users' device. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs. +Each Aztec function has access to a [context](../functions/context.md) object. This object, although labelled a global variable, is created locally on a users' device. It is initialized from the inputs provided by the kernel, and a hash of the function's inputs. #include_code context-example-context-return /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust @@ -64,7 +64,7 @@ We achieve this by pushing return values to the execution context, which we then **Making the contract's storage available** #include_code storage-example-context /yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr rust -When a [`Storage` struct](../storage/main.md) is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context. +When a [`Storage` struct](../storage/define_storage.md) is declared within a contract, the `storage` keyword is made available. As shown in the macro expansion above, this calls the init function on the storage struct with the current function's context. Any state variables declared in the `Storage` struct can now be accessed as normal struct members. @@ -75,9 +75,9 @@ This function takes the application context, and converts it into the `PrivateCi ## Unconstrained functions -Defining a function as `unconstrained` tells Aztec to simulate it completely client-side in the [ACIR simulator](../../../../learn/concepts/pxe/acir_simulator.md) without generating proofs. They are useful for extracting information from a user through an [oracle](./oracles.md). +Defining a function as `unconstrained` tells Aztec to simulate it completely client-side in the [ACIR simulator](../../../../learn/concepts/pxe/acir_simulator.md) without generating proofs. They are useful for extracting information from a user through an [oracle](../oracles/main.md). -When an unconstrained function is called, it prompts the ACIR simulator to +When an unconstrained function is called, it prompts the ACIR simulator to 1. generate the execution environment 2. execute the function within this environment @@ -86,15 +86,11 @@ To generate the environment, the simulator gets the blockheader from the [PXE da Once the execution environment is created, `execute_unconstrained_function` is invoked: -#include_code execute_unconstrained_function yarn-project/acir-simulator/src/client/unconstrained_execution.ts typescript +#include_code execute_unconstrained_function yarn-project/simulator/src/client/unconstrained_execution.ts typescript This: 1. Prepares the ACIR for execution 2. Converts `args` into a format suitable for the ACVM (Abstract Circuit Virtual Machine), creating an initial witness (witness = set of inputs required to compute the function). `args` might be an oracle to request a user's balance 3. Executes the function in the ACVM, which involves running the ACIR with the initial witness and the context. If requesting a user's balance, this would query the balance from the PXE database -4. Extracts the return values from the `partialWitness` and decodes them based on the artifact to get the final function output. The [artifact](../../artifacts.md) is the compiled output of the contract, and has information like the function signature, parameter types, and return types - - - - +4. Extracts the return values from the `partialWitness` and decodes them based on the artifact to get the final function output. The [artifact](../../compiling_contracts/artifacts.md) is the compiled output of the contract, and has information like the function signature, parameter types, and return types diff --git a/docs/docs/developers/contracts/syntax/functions/main.md b/docs/docs/developers/contracts/writing_contracts/functions/main.md similarity index 53% rename from docs/docs/developers/contracts/syntax/functions/main.md rename to docs/docs/developers/contracts/writing_contracts/functions/main.md index 17de123e35b..8164067e8cb 100644 --- a/docs/docs/developers/contracts/syntax/functions/main.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/main.md @@ -6,15 +6,27 @@ Functions serve as the building blocks of smart contracts. Functions can be eith For a more practical guide of using multiple types of functions, follow the [token tutorial](../../../tutorials/writing_token_contract.md). -Every smart contract has a private `constructor` function which is called when the contract is deployed. There are also special oracle functions, which can get data from outside of the smart contract. In the context of Aztec, oracles are often used to get user-provided inputs. - Currently, any function is "mutable" in the sense that it might alter state. In the future, we will support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). +## Constructors + +Every smart contract has a private `constructor` function which is called when the contract is deployed. + +A special constructor function must be declared within a contract's scope. + +A constructor doesn't have a name, because its purpose is clear: to initialize contract state. +In Aztec terminology, a constructor is always a 'private function' (i.e. it cannot be a public function). +A constructor behaves almost identically to any other function. It is just important for Aztec to be able to identify this function as special: it may only be called once, and will not be deployed as part of the contract. + +## Oracles + +There are also special oracle functions, which can get data from outside of the smart contract. In the context of Aztec, oracles are often used to get user-provided inputs. + Explore this section to learn: - [How function visibility works in Aztec](./visibility.md) - [Public, private, and unconstrained functions](./public_private_unconstrained.md), and how to write them -- How [constructors](./constructor.md) work and remain private -- [Calling functions from within the same smart contract and from different contracts](./calling_functions.md), including calling private functions from private functions, public from public, and even private from public -- [Oracles](./oracles) and how Aztec smart contracts might use them +- How to write a [constructor](./write_constructor.md) +- [Calling functions from within the same smart contract and from different contracts](./call_functions.md), including calling private functions from private functions, public from public, and even private from public +- [Oracles](../oracles/main.md) and how Aztec smart contracts might use them - [How functions work under the hood](./inner_workings.md) \ No newline at end of file diff --git a/docs/docs/developers/contracts/syntax/functions/public_private_unconstrained.md b/docs/docs/developers/contracts/writing_contracts/functions/public_private_unconstrained.md similarity index 90% rename from docs/docs/developers/contracts/syntax/functions/public_private_unconstrained.md rename to docs/docs/developers/contracts/writing_contracts/functions/public_private_unconstrained.md index 678fc7ad9d3..935a958cd8e 100644 --- a/docs/docs/developers/contracts/syntax/functions/public_private_unconstrained.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/public_private_unconstrained.md @@ -12,13 +12,13 @@ A public function is executed by the sequencer and has access to a state model t All data inserted into private storage from a public function will be publicly viewable (not private). ::: -To create a public function you can annotate it with the `#[aztec(public)]` attribute. This will make the [public context](../context.mdx) available within the function's execution scope. +To create a public function you can annotate it with the `#[aztec(public)]` attribute. This will make the [public context](./context.md) available within the function's execution scope. #include_code set_minter /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust ## `Private` Functions -A private function operates on private information, and is executed by the user. Annotate the function with the `#[aztec(private)]` attribute to tell the compiler it's a private function. This will make the [private context](../context.mdx#private-context-broken-down) available within the function's execution scope. +A private function operates on private information, and is executed by the user. Annotate the function with the `#[aztec(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. #include_code redeem_shield /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust @@ -32,4 +32,4 @@ Beyond using them inside your other functions, they are convenient for providing :::info Note, that unconstrained functions can have access to both public and private data when executed on the user's device. This is possible since it is not actually part of the circuits that are executed in contract execution. -::: \ No newline at end of file +::: diff --git a/docs/docs/developers/contracts/syntax/functions/visibility.md b/docs/docs/developers/contracts/writing_contracts/functions/visibility.md similarity index 100% rename from docs/docs/developers/contracts/syntax/functions/visibility.md rename to docs/docs/developers/contracts/writing_contracts/functions/visibility.md diff --git a/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md b/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md new file mode 100644 index 00000000000..868199b7015 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md @@ -0,0 +1,37 @@ +--- +title: How to write a constructor +--- + +This page explains how to write a constructor function. + +To learn more about constructors, read [this](./main.md#constructors). + +## Annotate with `#[aztec(private)]` + +Currently, all constructors in Aztec must be private. + +Define your constructor like so: + +```rust +#[aztec(private)] +fn constructor() +``` + +## Option 1: Empty constructor + +Your constructor does not need to do anything; you can leave it blank like so: + +```rust +#[aztec(private)] +fn constructor() {} +``` + +## Option 2: Constructor with logic + +Constructors are commonly used to set an admin, such as this example: + +#include_code constructor /yarn-project/noir-contracts/contracts/token_contract/src/main.nr rust + +Here, the constructor is calling a public function. It can also call a private function. Learn more about calling functions from functions [here](../functions/call_functions.md). + +To see constructors in action, check out the [Aztec.nr getting started guide](../../../getting_started/aztecnr-getting-started.md). \ No newline at end of file diff --git a/docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md b/docs/docs/developers/contracts/writing_contracts/historical_data/archive_tree/how_to_prove_history.md similarity index 66% rename from docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md rename to docs/docs/developers/contracts/writing_contracts/historical_data/archive_tree/how_to_prove_history.md index 8441611dbf2..4dc3711fbcd 100644 --- a/docs/docs/developers/contracts/syntax/historical_access/how_to_prove_history.md +++ b/docs/docs/developers/contracts/writing_contracts/historical_data/archive_tree/how_to_prove_history.md @@ -1,17 +1,19 @@ --- -title: How to prove existence of historical notes and nullifiers +title: How to use the Arhive Tree --- -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 an archive tree. You can learn more about how it works in the [concepts section](../../../../learn/concepts/storage/trees/main.md#archive-tree). +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 an archive tree. You can learn more about how it works in the [concepts section](../../../../../learn/concepts/storage/trees/main.md#archive-tree). + +View the History lib reference [here](../../../references/history_lib_reference.md). # History library The history library allows you to prove any of the following at a given block height before the current height: -* [Note inclusion](./history_lib_reference.md#note-inclusion) -* [Nullifier inclusion](./history_lib_reference.md#nullifier-inclusion) -* [Note validity](./history_lib_reference.md#note-validity) -* [Existence of public value](./history_lib_reference.md#public-value-inclusion) -* [Contract inclusion](./history_lib_reference.md#contract-inclusion) +* Note inclusion +* Nullifier inclusion +* Note validity +* Existence of public value +* Contract inclusion Using this library, you can check that specific notes or nullifiers were part of Aztec network state at specific blocks. This can be useful for things such as: @@ -25,7 +27,7 @@ Using this library, you can check that specific notes or nullifiers were part of * Prove a note was included in a specified block * Create a nullifier and prove it was not included in a specified block -For a more extensive reference, go to [the reference page](./history_lib_reference.md). +For a more extensive reference, go to [the reference page](../../../references/history_lib_reference.md). ## 1. Import the `history` library from `aztec` @@ -53,22 +55,17 @@ In this example, the user's notes are stored in a map called `private_values`. W ## 4. Prove that a note was included in a specified block -To prove that a note existed in a specified block, call `prove_note_inclusion` as shown in this example: +To prove that a note existed in a specified block, call `prove_note_inclusion_at` as shown in this example: #include_code prove_note_inclusion yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr rust -This function takes in 4 arguments: - -1. The note interface (`ValueNoteMethods`) -2. The note (`maybe_note.unwrap_unchecked()`). Here, `unwrap_unchecked()` returns the inner value without asserting `self.is_some()` -3. The block number -4. Private context - -Note: for this to work, you will need to import `ValueNoteMethods` at the beginning of the contract: +This function takes in 3 arguments: -#include_code value_note_imports yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr rust +1. The note (`maybe_note.unwrap_unchecked()`). Here, `unwrap_unchecked()` returns the inner value without asserting `self.is_some()` +2. The block number +3. Private context -This will only prove the note existed, not whether or not the note has been nullified. You can prove that a note existed and had not been nullified in a specified block by using `prove_note_validity` which takes the same arguments: +This will only prove the note existed at the specific block number, not whether or not the note has been nullified. You can prove that a note existed and had not been nullified in a specified block by using `prove_note_validity_at` which takes the same arguments: #include_code prove_note_validity yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr rust @@ -84,7 +81,7 @@ You can then compute this nullifier with `note.compute_nullifier(&mut context)`. ## 6. Prove that a nullifier was included in a specified block -Call `prove_nullifier_inclusion` like so: +Call `prove_nullifier_inclusion_at` like so: #include_code prove_nullifier_inclusion yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr rust @@ -93,10 +90,8 @@ This takes three arguments: 2. Block number 3. Private context -You can also prove that a nullifier was not included in a specified block by using `prove_nullifier_non_inclusion` which takes the same arguments: - -#include_code prove_nullifier_non_inclusion yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr rust +You can also prove that a nullifier was not included in a specified block by using `prove_nullifier_not_included_at` which takes the same arguments. -## Prove contract inclusion, public value inclusion, and note commitment inclusion +## Prove contract inclusion, public value inclusion, and use current state in lookups -To see what else you can do with the `history` library, check out the [reference](./history_lib_reference.md). +To see what else you can do with the `history` library, check out the [reference](../../../references/history_lib_reference.md). diff --git a/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/implement_slow_updates.md b/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/implement_slow_updates.md new file mode 100644 index 00000000000..ce6d4710ced --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/implement_slow_updates.md @@ -0,0 +1,63 @@ +--- +title: How to implement a Slow Updates Tree +--- + +To learn more about the Slow Updates Tree, go [here](./main.md) + +On this page you will learn how to implement a slow updates tree into your contract, and an example of a token blacklisting contract that uses the slow updates tree. + +# How to implement a slow updates tree + +1. Copy the *SlowTree.nr* example and its dependencies, found [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/slow_tree_contract). Replace the constants with whatever you like and deploy it to your sandbox +2. Copy the *SlowMap interface* for easy interaction with your deployed SlowTree. Find it [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr) +3. Import this interface into your contract + +#include_code interface yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +5. Store the SlowTree address in private storage as a FieldNote + +#include_code constructor yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +6. Store the SlowTree address in public storage and initialize an instance of SlowMap using this address + +#include_code write_slow_update_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +7. Now you can read and update from private functions: + +#include_code get_and_update_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +8. Or from public functions: + +#include_code get_public yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +View the [reference](../../../references/slow_updates_tree.md) for more information. + +## Exploring an example integration through a **`TokenBlacklist`** Smart Contract + +The `TokenBlacklist` contract is a token contract that does not allow blacklisted accounts to perform mints or transfers. In this section we will go through how this is achieved through the slow updates tree. + +You can find the full code for the TokenBlacklist smart contract [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/token_blacklist_contract). + +### Importing SlowMap + +The contract first imports the **`SlowMap`** interface: + +#include_code interface yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +This interface allows the contract to interact with its attached SlowTree. It abstracts these functions so they do not have to be implemented in the TokenBlacklist contract. + +### Constructor and initialization + +The contract's constructor takes the address of the slow updates contract: + +#include_code constructor yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +This initialization sets up the connection between the **`TokenBlacklist`** contract and a previously deployed SlowTree, allowing it to use the interface to directly interact with the SlowTree. + +### Private transfer function utilizing the slow updates tree + +In the private transfer function, the contract uses the interface to check if a user is blacklisted: + +#include_code transfer_private yarn-project/noir-contracts/contracts/token_blacklist_contract/src/main.nr rust + +Here, the contract reads the roles of the sender and recipient from the SlowTree using the **`read_at`** function in the interface. It checks if either party is blacklisted, and if so, the transaction does not go ahead. diff --git a/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/main.md b/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/main.md new file mode 100644 index 00000000000..6c40f80c440 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/historical_data/slow_updates_tree/main.md @@ -0,0 +1,81 @@ +--- +title: Slow Updates Tree +--- + +Slow Updates Tree is a data structure that allows for historical public data to be accessed in both private and public domains. Read the high level overview in the [Communication section](../../../../../learn/concepts/communication/public_private_calls/slow_updates_tree.md). This page explains the components involved. + +If you want to integrate it in your contract, follow this [guide](../slow_updates_tree/implement_slow_updates.md). + +The slow updates tree works by having a current tree and a pending tree, and replacing the current tree with the pending tree after an epoch has passed. Public functions can read directly from the current tree, and private functions can perform a membership proof that values are part of a commitment to the current state of the tree. + +# Components involved in implementing a slow updates tree + +There are generally 4 main components involved to make it easier to use a slow updates tree, with 3 already implemented by Aztec. This makes it easier to interact with a slow updates tree through a simple interface. These four components are: + +## Main smart contract + +This is the primary smart contract that will use the slow updates tree. In the example we use a [token with blacklisting features](./implement_slow_updates.md#exploring-an-example-integration-through-a-tokenblacklist-smart-contract). + +## Interface + +This interface of the slow updates tree contract allows your contract to interact with the Slow Updates Tree contract. It provides methods for reading and updating values in the tree in both public and private contexts. You can find it [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_blacklist_contract/src/interfaces.nr). + +## SlowTree.nr contract + +This is a smart contract developed by Aztec that establishes and manages a slow updates tree structure. It allows developers to access and interact with the tree, such as reading and updating data. + +You can find it [here](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/noir-contracts/contracts/slow_tree_contract). + +## SlowMap type + +This is a type in the Aztec.nr library that is utilized by the SlowTree contract. It defines the underlying data structure for the slow updates tree, and handles storing both the current and pending values for each data entry. + +You can find it [here](https://github.com/AztecProtocol/aztec-nr/blob/master/slow-updates-tree/src/slow_map.nr). + +The diagram below describes how these components work together. It does not contain all the functionality. + +```mermaid +graph TD + MSC[Main Smart Contract] --> INT[Interface] + STC --> SMT + + INT_RAP[read_at_pub] <--> STC_RAP[read_at_public] + INT_RA[read_at] <--> STC_RA[read_at] + INT_UAP[update_at_public] <--> STC_UAP[update_at_public] + INT_UA[update_at_private] <--> STC_UA[update_at_private] + + STC_RA <--> VMP[verify_membership_proof] + STC_UA <--> CR[compute_roots] + + subgraph INT[Interface] + INT_RAP + INT_UAP + INT_RA + INT_UA + end + + subgraph STC[SlowTree.nr] + STC_RAP + STC_UAP + STC_RA + STC_UA + end + + subgraph SMT[SlowMap Type] + Change{Epoch Over} -->|True| Current{Current} + Change -->|False| Pending{Pending} + Current --> Current1[Current Commitment 1] + Current --> CurrentM[Current Commitment M] + CurrentM --> Value1[Current Value 1] + CurrentM --> Value2[Current Value 2] + CurrentM --> ValueN[Current Value N] + Pending --> PendingM[Pending Commitment 1] + PendingM --> PValue1[Pending Value 1] + PendingM --> PValue2[Pending Value 2] + PendingM --> PValueN[Pending Value N] + end + + style INT fill:#fff,stroke:#333,stroke-width:1px + style STC fill:#fff,stroke:#333,stroke-width:1px + style SMT fill:#fff,stroke:#333,stroke-width:1px +``` \ No newline at end of file diff --git a/docs/docs/developers/contracts/layout.md b/docs/docs/developers/contracts/writing_contracts/layout.md similarity index 61% rename from docs/docs/developers/contracts/layout.md rename to docs/docs/developers/contracts/writing_contracts/layout.md index 48fbc9a7030..d8bdd16387a 100644 --- a/docs/docs/developers/contracts/layout.md +++ b/docs/docs/developers/contracts/writing_contracts/layout.md @@ -1,8 +1,8 @@ --- -title: Structure +title: Structure of a contract --- -A contract is a collection of persistent [state variables](./syntax/storage/main.md), and [functions](./syntax/functions/main.md) 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. +A contract is a collection of persistent [state variables](../references/storage/main.md), and [functions](./functions/main.md) 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. # Contract @@ -35,4 +35,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 token contract tutorial [here](../tutorials/writing_token_contract.md). +- You can review the structure of a complete contract in the token contract tutorial [here](../../tutorials/writing_token_contract.md). diff --git a/docs/docs/developers/contracts/syntax/oracles.md b/docs/docs/developers/contracts/writing_contracts/oracles/inbuilt_oracles.md similarity index 54% rename from docs/docs/developers/contracts/syntax/oracles.md rename to docs/docs/developers/contracts/writing_contracts/oracles/inbuilt_oracles.md index fa524a02bc8..6f8a40b23bc 100644 --- a/docs/docs/developers/contracts/syntax/oracles.md +++ b/docs/docs/developers/contracts/writing_contracts/oracles/inbuilt_oracles.md @@ -1,18 +1,12 @@ --- -title: Oracles +title: Inbuilt Oracles --- -On this page you will learn: - -1. [A list of inbuilt oracles](#inbuilt-oracles) -3. [How to use the debug_log oracle](#how-to-use-the-debug-oracle) -3. [How to use the auth_witness oracle](#how-to-use-the-auth_witness-oracle) -4. [How to use the pop_capsule oracle for arbitrary data](#how-to-use-the-popCapsule-oracle) -4. [Reference](#oracles-reference) +This page goes over all the oracles that are available in Aztec.nr. If you'd like to read more about what oracles are, check out [this page](../oracles/main.md). ## Inbuilt oracles -- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/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](../../debugging/main.md). +- [`debug_log`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/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](../../../debugging/main.md#logging-in-aztecnr). - [`auth_witness`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/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/yarn-project/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/yarn-project/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. @@ -20,30 +14,4 @@ On this page you will learn: Find a full list [on GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/aztec-nr/aztec/src/oracle). -:::note -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](#how-to-use-the-pop_capsule-oracle). -::: - -## How to use the popCapsule oracle - -`popCapsule` is used for passing artbitrary data. We have not yet included this in Aztec.nr, so it is a bit more complex than the other oracles. You can follow this how-to: - -### 1. Define the pop_capsule function - -In a new file on the same level as your `main.nr`, implement an unconstrained function that calls the pop_capsule oracle: - -#include_code pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/capsule.nr rust - -### 2. Import this into your smart contract - -If it lies in the same directory as your smart contract, you can import it like this: - -#include_code import_pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr rust - -### 3. Use it as any other oracle - -Now it becomes a regular oracle you can call like this: - -#include_code pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr rust - - +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](./pop_capsule.md). \ No newline at end of file diff --git a/docs/docs/developers/contracts/syntax/functions/oracles.md b/docs/docs/developers/contracts/writing_contracts/oracles/main.md similarity index 97% rename from docs/docs/developers/contracts/syntax/functions/oracles.md rename to docs/docs/developers/contracts/writing_contracts/oracles/main.md index 28a57bed1d6..673dbfce389 100644 --- a/docs/docs/developers/contracts/syntax/functions/oracles.md +++ b/docs/docs/developers/contracts/writing_contracts/oracles/main.md @@ -4,7 +4,7 @@ title: Oracle Functions 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](../oracles.md). +Looking for a hands-on guide? You can learn how to use oracles in a smart contract [here](./pop_capsule.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. diff --git a/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md b/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md new file mode 100644 index 00000000000..f7d4c02c800 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/oracles/pop_capsule.md @@ -0,0 +1,29 @@ +--- +title: How to use the popCapsule oracle +--- + +On this page you will learn how to use the `popCapsule` oracle. To see what other oracles are available in Aztec.nr, go [here](./inbuilt_oracles.md). + +## How to use the popCapsule oracle + +`popCapsule` is used for passing artbitrary data. We have not yet included this in Aztec.nr, so it is a bit more complex than the other oracles. You can follow this how-to: + +### 1. Define the pop_capsule function + +In a new file on the same level as your `main.nr`, implement an unconstrained function that calls the pop_capsule oracle: + +#include_code pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/capsule.nr rust + +### 2. Import this into your smart contract + +If it lies in the same directory as your smart contract, you can import it like this: + +#include_code import_pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr rust + +### 3. Use it as any other oracle + +Now it becomes a regular oracle you can call like this: + +#include_code pop_capsule yarn-project/noir-contracts/contracts/slow_tree_contract/src/main.nr rust + + diff --git a/docs/docs/developers/contracts/portals/main.md b/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md similarity index 92% rename from docs/docs/developers/contracts/portals/main.md rename to docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md index 11fc1c0b9de..d2e62dedda1 100644 --- a/docs/docs/developers/contracts/portals/main.md +++ b/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md @@ -1,17 +1,14 @@ --- -title: Portals -description: Documentation of Aztec's Portals and Cross-chain communication. +title: Communicating with L1 --- -## What is a portal +Is this your first time hearing the word `Portal`? Check out the [concepts section](../../../../learn/concepts/communication/cross_chain_calls.md). -A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. - -As outlined in [Communication](../../../learn/concepts/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. +Follow the [token bridge tutorial](../../../tutorials/token_portal/main.md) for hands-on experience writing and deploying a Portal contract. ## Passing data to the rollup -Whether it is tokens or other information being passed to the rollup, the portal should use the [`Inbox`](./inbox.md) to do it. +Whether it is tokens or other information being passed to the rollup, the portal should use the `Inbox` to do it. The `Inbox` can be seen as a mailbox to the rollup, portals put messages into the box, and the sequencers then decide which of these message they want to include in their blocks (each message has a fee attached to it, so there is a fee market here). @@ -42,7 +39,7 @@ To consume the message, we can use the `consume_l1_to_l2_message` function withi Note that while the `secret` and the `content` are both hashed, they are actually hashed with different hash functions! ::: -#include_code context_consume_l1_to_l2_message /yarn-project/aztec-nr/aztec/src/context.nr rust +#include_code context_consume_l1_to_l2_message /yarn-project/aztec-nr/aztec/src/context/private_context.nr rust Computing the `content` must be done manually in its current form, as we are still adding a number of bytes utilities. A good example exists within the [Token bridge example](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_bridge_contract/src/util.nr). @@ -78,7 +75,7 @@ The portal must ensure that the sender is as expected. One way to do this is to To send a message to L1 from your Aztec contract, you must use the `message_portal` function on the `context`. When messaging to L1, only the `content` is required (as a `Field`). -#include_code context_message_portal /yarn-project/aztec-nr/aztec/src/context.nr rust +#include_code context_message_portal /yarn-project/aztec-nr/aztec/src/context/private_context.nr rust When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). @@ -100,17 +97,6 @@ As noted earlier, the portal contract should check that the sender is as expecte #include_code token_portal_withdraw l1-contracts/test/portals/TokenPortal.sol solidity -## How to deploy a contract with a portal - -- Deploy to L1 using Viem, Foundry or your preferred tool; -- Deploy to L2 passing in the address of the L1 portal as its portal contract; - ```typescript - const deploymentTx = Contract.deploy(wallet).send({ - portalContract: tokenPortalAddress, - }); - ``` -- Initialize l1 with l2 address for access control. - ## Considerations ### Structure of messages diff --git a/docs/docs/developers/contracts/writing_contracts/portals/deploy_with_portal.md b/docs/docs/developers/contracts/writing_contracts/portals/deploy_with_portal.md new file mode 100644 index 00000000000..2277e588fac --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/portals/deploy_with_portal.md @@ -0,0 +1,14 @@ +--- +title: How to deploy a contract with a Portal +--- + +- Deploy to L1 using Viem, Foundry or your preferred tool; +- Deploy to L2 passing in the address of the L1 portal as its portal contract; + ```typescript + const deploymentTx = Contract.deploy(wallet).send({ + portalContract: tokenPortalAddress, + }); + ``` +- Initialize l1 with l2 address for access control. + +Follow the [token bridge tutorial](../../../tutorials/token_portal/main.md) for hands-on experience writing and deploying a Portal contract. \ No newline at end of file diff --git a/docs/docs/developers/contracts/writing_contracts/portals/portals.md b/docs/docs/developers/contracts/writing_contracts/portals/portals.md new file mode 100644 index 00000000000..642bad03eb4 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/portals/portals.md @@ -0,0 +1,7 @@ +--- +title: Portals +--- + +A portal is the point of contact between L1 and a specific contract on Aztec. For applications such as token bridges, this is the point where the tokens are held on L1 while used in L2. + +As outlined in [Communication](../../../../learn/concepts/communication/cross_chain_calls.md), an Aztec L2 contract is linked to _ONE_ L1 address at time of deployment (specified by the developer). This L1 address is the only address that can send messages to that specific L2 contract, and the only address that can receive messages sent from the L2 contract to L1. Note, that a portal don't actually need to be a contract, it could be any address on L1. We say that an Aztec contract is attached to a portal. diff --git a/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md b/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md new file mode 100644 index 00000000000..49804252051 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md @@ -0,0 +1,47 @@ +--- +title: How to define contract storage +--- + +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](../../../../learn/concepts/storage/storage_slots.md). + +[See the storage reference](../../references/storage/main.md). + +:::info +The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). +::: + +```rust +struct Storage { + // public state variables + // private state variables +} +``` + +:::danger +If your contract uses storage (has Storage struct defined), you **MUST** include a `compute_note_hash_and_nullifier` function to allow PXE to process encrypted events. See [encrypted events](../events/emit_event.md#successfully-process-the-encrypted-event) for more. + +If you don't yet have any private state variables defined you can use this placeholder function: + +#include_code compute_note_hash_and_nullifier_placeholder /yarn-project/noir-contracts/contracts/token_bridge_contract/src/main.nr rust +::: + +Since Aztec.nr is written in Noir, which is state-less, we need to specify how the storage struct should be initialized to read and write data correctly. This is done by specifying an `init` function that is run in functions that rely on reading or altering the state variables. This `init` function must declare the Storage struct with an instantiation defining how variables are accessed and manipulated. The function MUST be called `init` for the Aztec.nr library to properly handle it (this will be relaxed in the future). + +```rust +impl Storage { + fn init(context: Context) -> Self { + Storage { + // (public state variables)::new() + // (private state variables)::new() + } + } +} +``` + +If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions. + +:::warning Using slot `0` is not supported! +No storage values should be initialized at slot `0` - storage slots begin at `1`. This is a known issue that will be fixed in the future. +::: diff --git a/docs/docs/developers/contracts/writing_contracts/storage/main.md b/docs/docs/developers/contracts/writing_contracts/storage/main.md new file mode 100644 index 00000000000..df4574040d1 --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/storage/main.md @@ -0,0 +1,12 @@ +--- +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. + +You control this storage in Aztec using the Storage struct. 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. + +## Continue reading + +- Learn how to define a storage struct [here](./define_storage.md) +- View the storage reference with all variable types [here](../../references/storage/main.md) \ No newline at end of file diff --git a/docs/docs/developers/contracts/syntax/storage/storage_slots.md b/docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md similarity index 100% rename from docs/docs/developers/contracts/syntax/storage/storage_slots.md rename to docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md diff --git a/docs/docs/developers/getting_started/aztecjs-getting-started.md b/docs/docs/developers/getting_started/aztecjs-getting-started.md index d2f1fd6c2e6..1efb1b0742e 100644 --- a/docs/docs/developers/getting_started/aztecjs-getting-started.md +++ b/docs/docs/developers/getting_started/aztecjs-getting-started.md @@ -1,5 +1,5 @@ --- -title: Getting Started with Aztec.js +title: An introduction to Aztec.js --- import Image from "@theme/IdealImage"; @@ -375,4 +375,4 @@ That's it! We have successfully deployed a token contract to an instance of the ## Next Steps -Learn more about writing Aztec.nr contracts in the [Aztec.nr getting started guide](./aztecnr-getting-started.md). +Learn more about writing Aztec.nr contracts on the [next page](./aztecnr-getting-started.md). diff --git a/docs/docs/developers/getting_started/aztecnr-getting-started.md b/docs/docs/developers/getting_started/aztecnr-getting-started.md index 5235e2942e4..0bd535ec764 100644 --- a/docs/docs/developers/getting_started/aztecnr-getting-started.md +++ b/docs/docs/developers/getting_started/aztecnr-getting-started.md @@ -1,5 +1,5 @@ --- -title: Getting Started with Aztec.nr +title: Writing your first smart contract --- In this guide, we will create our first Aztec.nr smart contract. We will build a simple private counter. This contract will get you started with the basic setup and syntax of Aztec.nr, but doesn't showcase the awesome stuff Aztec is capable of. @@ -80,7 +80,7 @@ Context gives us access to the environment information such as `msg.sender`. We `map::Map` -Map is a private state variable that functions like a dictionary, relating Fields to other state variables. You can learn more about it [here](../contracts/syntax/main.md). +Map is a private state variable that functions like a dictionary, relating Fields to other state variables. `value_note` @@ -102,7 +102,7 @@ Let’s create a `constructor` method to run on deployment that assigns an initi This function accesses the counts from storage. Then it assigns the passed initial counter to the `owner`'s counter privately using `at().add()`. -We have annotated this and other functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](../contracts/syntax/functions/main.md). +We have annotated this and other functions with `#[aztec(private)]` which are ABI macros so the compiler understands it will handle private inputs. Learn more about functions and annotations [here](../contracts/writing_contracts/functions/main.md). ## Incrementing our counter @@ -183,7 +183,7 @@ Partial Address: 0x211edeb823ef3e042e91f338d0d83d0c90606dba16f678c701d8bb64e64e2 Use one of these `address`es as the `owner`. You can either copy it or export. -To deploy the counter contract, [ensure the sandbox is running](../cli/sandbox-reference.md) and run this in the root of your Noir project: +To deploy the counter contract, [ensure the sandbox is running](../sandbox/references/sandbox-reference.md) and run this in the root of your Noir project: ```bash aztec-cli deploy contracts/counter/src/artifacts/Counter.json --args 100 0x2a0f32c34c5b948a7f9766f0c1aad70a86c0ee649f56208e936be4324d49b0b9 @@ -211,11 +211,11 @@ Now you can explore. **Interested in learning more about how Aztec works under the hood?** -Understand the high level architecture [here](../../learn/about_aztec/technical_overview.md). +Understand the high level architecture on the [Core Components page](../../learn/about_aztec/technical_overview.md). You can also explore Aztec's [hybrid state model](../../learn/concepts/hybrid_state/main.md) and [the lifecycle of a transaction](../../learn/concepts/transactions.md). -**Want to write more advanced smart contracts?** +**Want to write more contracts?** -Follow the token contract tutorial [here](../tutorials/writing_token_contract.md). +Follow the series of tutorials, starting with the private voting contract [here](../tutorials/writing_private_voting_contract.md). **Ready to dive into Aztec and Ethereum cross-chain communication?** diff --git a/docs/docs/developers/getting_started/main.md b/docs/docs/developers/getting_started/main.md index 0e6fa1844ed..4d18453d50a 100644 --- a/docs/docs/developers/getting_started/main.md +++ b/docs/docs/developers/getting_started/main.md @@ -12,7 +12,7 @@ If this is your first time using Aztec, and you want to get started by learning ## Learn -If you want to read more about the high level concepts of Aztec before writing some code, head to the [Concepts section](../../learn/about_aztec/technical_overview.md). +If you want to read more about the high level concepts of Aztec before writing some code, head over to the [Core Components section](../../learn/about_aztec/technical_overview.md). ## In this section diff --git a/docs/docs/developers/getting_started/quickstart.md b/docs/docs/developers/getting_started/quickstart.md index a7f1f894916..6f22059ce4f 100644 --- a/docs/docs/developers/getting_started/quickstart.md +++ b/docs/docs/developers/getting_started/quickstart.md @@ -95,6 +95,6 @@ Congratulations! You are all set up with the Aztec sandbox! ## What's next? -To start writing your first Aztec.nr smart contract, go to the [next page](aztecnr-getting-started.md). +To deploy and interact with a contract using Aztec.js, go to the [next page](aztecnr-getting-started.md). -You can also dig more into the sandbox and CLI [here](../cli/main.md). +You can also dig more into the sandbox and CLI [here](../sandbox/main.md). diff --git a/docs/docs/developers/limitations/main.md b/docs/docs/developers/limitations/main.md index 4101aeeb6d9..0147994b05a 100644 --- a/docs/docs/developers/limitations/main.md +++ b/docs/docs/developers/limitations/main.md @@ -29,13 +29,13 @@ Help shape and define: - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/syntax/functions/constructor.md). -- No static nor delegate calls (see [mutability](../contracts/syntax/functions/main.md)). + - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/writing_contracts/functions/write_constructor.md). +- No static nor delegate calls (see [mutability](../contracts/writing_contracts/functions/main.md)). - These values are unused in the call-context. - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/syntax/context.mdx). -- The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](../contracts/syntax/functions/visibility.md). + - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/writing_contracts/functions/context.md). +- The initial `msg_sender` is 0, which can be problematic for some contracts, see [function visibility](../contracts/writing_contracts/functions/visibility.md). - Unencrypted logs don't link to the contract that emitted it, so essentially just a `debug_log`` that you can match values against. - A note that is created and nullified in the same transaction will still emit an encrypted log. - A limited amount of new commitments, nullifiers and calls that are supported by a transaction, see [circuit limitations](#circuit-limitations). @@ -193,7 +193,7 @@ Here are the current constants: #### What are the consequences? -When you write an [Aztec.nr](../contracts/main.md) [function](../contracts/syntax/functions/main.md), there will be upper bounds on the following: +When you write an [Aztec.nr](../contracts/main.md) [function](../contracts/writing_contracts/functions/main.md), there will be upper bounds on the following: - The number of public state reads and writes; - The number of note reads and nullifications; diff --git a/docs/docs/developers/privacy/main.md b/docs/docs/developers/privacy/main.md index ab58316956a..d7d2997df55 100644 --- a/docs/docs/developers/privacy/main.md +++ b/docs/docs/developers/privacy/main.md @@ -49,7 +49,7 @@ Any time a private function makes a call to a public function, information is le ### Crossing the public -> private boundary -If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](../contracts/portals/inbox.md) for more details. +If a public function sends a message to be consumed by a private function, the act of consuming that message might be leaked if not following recommended patterns. See [here](../contracts/references/portals/inbox.md) for more details. ### Timing of transactions diff --git a/docs/docs/developers/cli/blank_box.md b/docs/docs/developers/sandbox/guides/blank_box.md similarity index 93% rename from docs/docs/developers/cli/blank_box.md rename to docs/docs/developers/sandbox/guides/blank_box.md index 94ceb1d7eca..6838786c1da 100644 --- a/docs/docs/developers/cli/blank_box.md +++ b/docs/docs/developers/sandbox/guides/blank_box.md @@ -1,5 +1,5 @@ --- -title: Aztec Boxes +title: Run a blank Aztec Box --- This page will go over Aztec Boxes, which are full stack Aztec project templates that come with: @@ -16,11 +16,11 @@ There are also boxes that include a basic React interface (`blank-react`) and an ## Setup -See the Quickstart page for [requirements](../getting_started/quickstart.md#requirements), starting the local [Sandbox environment](../getting_started/quickstart.md#sandbox-installation) and [installing the CLI](../getting_started/quickstart#cli-installation). +See the Quickstart page for [requirements](../../getting_started/quickstart.md#requirements), starting the local [Sandbox environment](../../getting_started/quickstart.md#sandbox-installation) and [installing the CLI](../../getting_started/quickstart#cli-installation). Aztec Boxes use [yarn](https://classic.yarnpkg.com/) for package management, so if you want to follow along exactly, make sure you have it [installed](https://classic.yarnpkg.com/en/docs/install). -You will also need to install Aztec tooling to compile contracts. You can find instructions for installing the latest version [here](../cli/sandbox-reference.md). +You will also need to install Aztec tooling to compile contracts. You can find instructions for installing the latest version [here](../../sandbox/references/sandbox-reference.md). ## Getting the Box @@ -68,7 +68,7 @@ yarn ### Start the Sandbox -See the Quickstart for [installing and starting the Sandbox](../getting_started/quickstart.md#sandbox-installation). +See the Quickstart for [installing and starting the Sandbox](../../getting_started/quickstart.md#sandbox-installation). ### Start the frontend diff --git a/docs/docs/developers/cli/run_more_than_one_pxe_sandbox.md b/docs/docs/developers/sandbox/guides/run_more_than_one_pxe_sandbox.md similarity index 73% rename from docs/docs/developers/cli/run_more_than_one_pxe_sandbox.md rename to docs/docs/developers/sandbox/guides/run_more_than_one_pxe_sandbox.md index c53a082b3e1..7961f659f7a 100644 --- a/docs/docs/developers/cli/run_more_than_one_pxe_sandbox.md +++ b/docs/docs/developers/sandbox/guides/run_more_than_one_pxe_sandbox.md @@ -19,17 +19,11 @@ This removes any other arguments, allowing you to ensure an isolated environment In another terminal, run: ```bash -docker-compose run -e MODE=pxe -e PXE_PORT=8085 -e AZTEC_NODE_URL='http://aztec-aztec-1:8079' -e TEST_ACCOUNTS='false' -p 8085:8085 aztec +aztec start --pxe nodeUrl=http://aztec-aztec-1:8079 ``` -This does a few things: -* Starts in PXE mode -* Passes the current Aztec node URL -* Does not load new test accounts -* Sets a port to listen on -* Only runs Aztec PXE, not Ethereum This command uses the default ports, so they might need to be changed depending on yuor configuration. -You can learn more about custom commands in the [sandbox reference](./sandbox-reference.md). +You can learn more about custom commands in the [sandbox reference](../references/sandbox-reference.md). diff --git a/docs/docs/developers/cli/main.md b/docs/docs/developers/sandbox/main.md similarity index 96% rename from docs/docs/developers/cli/main.md rename to docs/docs/developers/sandbox/main.md index a10ff03e281..f0f3bdd22c1 100644 --- a/docs/docs/developers/cli/main.md +++ b/docs/docs/developers/sandbox/main.md @@ -38,4 +38,4 @@ The Aztec CLI is a command-line tool allowing you to interact directly with the It aims to provide all of the functionality required to deploy, and invoke contracts and query system state such as contract data, transactions and emitted logs. -Use `aztec-nargo` for compiling contracts. See the [compiling contracts](../contracts/compiling.md) page for more information. +Use `aztec-nargo` for compiling contracts. See the [compiling contracts](../contracts/compiling_contracts/how_to_compile_contract.md) page for more information. diff --git a/docs/docs/developers/testing/cheat_codes.md b/docs/docs/developers/sandbox/references/cheat_codes.md similarity index 99% rename from docs/docs/developers/testing/cheat_codes.md rename to docs/docs/developers/sandbox/references/cheat_codes.md index 834685210f8..d9c04dddfd9 100644 --- a/docs/docs/developers/testing/cheat_codes.md +++ b/docs/docs/developers/sandbox/references/cheat_codes.md @@ -565,5 +565,5 @@ Keep up with the latest discussion and join the conversation in the [Aztec forum You can also use the above link to request more cheatcodes. -import Disclaimer from "../../misc/common/\_disclaimer.mdx"; +import Disclaimer from "../../../misc/common/\_disclaimer.mdx"; diff --git a/docs/docs/developers/cli/cli-commands.md b/docs/docs/developers/sandbox/references/cli-commands.md similarity index 94% rename from docs/docs/developers/cli/cli-commands.md rename to docs/docs/developers/sandbox/references/cli-commands.md index 83c107365d8..6f8d13e965a 100644 --- a/docs/docs/developers/cli/cli-commands.md +++ b/docs/docs/developers/sandbox/references/cli-commands.md @@ -37,15 +37,15 @@ The update command won't update the CLI itself. To update these follow the [upda ## Compile -You can find more information about compiling contracts [on this page](../contracts/compiling.md). +You can find more information about compiling contracts [on this page](../../contracts/compiling_contracts/how_to_compile_contract.md). ## Creating Accounts -The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../learn/concepts/accounts/keys.md): +The first thing we want to do is create a couple of accounts. We will use the `create-account` command which will generate a new private key for us, register the account on the sandbox, and deploy a simple account contract which [uses a single key for privacy and authentication](../../../learn/concepts/accounts/keys.md): #include_code create-account yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash -Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). +Once the account is set up, the CLI returns the resulting address, its privacy key, and partial address. You can read more about these [here](../../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-keys). Save the Address and Private key as environment variables. We will be using them later. @@ -72,7 +72,7 @@ export ADDRESS2= ## Deploying a Token Contract -We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. You can find the contract we are deploying [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) (or write it for yourself in [this tutorial!](../tutorials/writing_token_contract.md)) +We will now deploy a token contract using the `deploy` command, and set an address of the admin via a constructor argument. You can find the contract we are deploying [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/noir-contracts/contracts/token_contract/src/main.nr) (or write it for yourself in [this tutorial!](../../tutorials/writing_token_contract.md)) Make sure to replace this address with one of the two you created earlier. #include_code deploy yarn-project/end-to-end/src/cli_docs_sandbox.test.ts bash diff --git a/docs/docs/developers/cli/sandbox-reference.md b/docs/docs/developers/sandbox/references/sandbox-reference.md similarity index 96% rename from docs/docs/developers/cli/sandbox-reference.md rename to docs/docs/developers/sandbox/references/sandbox-reference.md index 8fb0866d331..b1ed012f56c 100644 --- a/docs/docs/developers/cli/sandbox-reference.md +++ b/docs/docs/developers/sandbox/references/sandbox-reference.md @@ -6,7 +6,7 @@ Here you will find a reference to everything available within the Sandbox. ## Installation -You can run the Sandbox using Docker. See the [Quickstart](../getting_started/quickstart.md#install-docker) for instructions on installing Docker. +You can run the Sandbox using Docker. See the [Quickstart](../../getting_started/quickstart.md#install-docker) for instructions on installing Docker. ### With Docker @@ -172,7 +172,7 @@ To help with testing, the sandbox is shipped with a set of cheatcodes. Cheatcodes allow you to change the time of the Aztec block, load certain state or more easily manipulate Ethereum instead of having to write dedicated RPC calls to anvil or hardhat. -You can find the cheat code reference [here](../testing/cheat_codes.md). +You can find the cheat code reference [here](../../sandbox/references/cheat_codes.md). ## Contracts @@ -215,4 +215,4 @@ You can see all of our example contracts in the monorepo [here](https://github.c The sandbox is shipped with full-stack Aztec project templates, with example Aztec.nr contracts, testing scripts, and web interfaces. -You can read more information about how to use boxes [here](./blank_box.md). +You can read more information about how to use boxes [here](../guides/blank_box.md). diff --git a/docs/docs/developers/testing/main.md b/docs/docs/developers/testing/main.md deleted file mode 100644 index 5413e63cd3d..00000000000 --- a/docs/docs/developers/testing/main.md +++ /dev/null @@ -1,5 +0,0 @@ -import DocCardList from '@theme/DocCardList'; - -# Testing - - diff --git a/docs/docs/developers/tutorials/main.md b/docs/docs/developers/tutorials/main.md index c294167c9d2..69dc1513793 100644 --- a/docs/docs/developers/tutorials/main.md +++ b/docs/docs/developers/tutorials/main.md @@ -2,6 +2,46 @@ title: Tutorials --- -import DocCardList from '@theme/DocCardList'; +This section will guide you through all aspects of Aztec. You'll be building Aztec.nr contracts, writing tests with Aztec.js, and exploring more aspects of the sandbox on the way. - +It is recommended to follow them in order, beginning with the [private voting contract](writing_private_voting_contract.md) through to the [uniswap contract with e2e test](./uniswap/main.md). + +Here's an overview of what you'll learn in each: + +## Writing a private voting smart contract in Aztec.nr + +- Interacting with hybrid state in Aztec.nr +- Access control +- Writing custom nullifiers + +[Check it out](./writing_private_voting_contract.md). + +## Writing a token contract in Aztec.nr + +- More complex types and interactions in Aztec.nr +- How a real smart contract could look +- A theoretical look at cross-chain interactions + +[Check it out](./writing_token_contract.md). + +## Writing a DApp + +- How all the pieces of Aztec fit together +- Structuring an Aztec project + +[Check it out](./writing_dapp/main.md). + +## Build a Token Bridge + +- Public and private cross-chain communication with Ethereum +- More details into what the Sandbox is capable of + +[Check it out](./token_portal/main.md). + +## Swap on L1 Uniswap from L2 with Portals + +- A more complex example of cross-chain communication + +Note - this builds on the code previously written in the Token Bridge tutorial. + +[Check it out](./uniswap/main.md). diff --git a/docs/docs/developers/tutorials/testing.md b/docs/docs/developers/tutorials/testing.md index 3b19d4c3bb7..e0ec74a519b 100644 --- a/docs/docs/developers/tutorials/testing.md +++ b/docs/docs/developers/tutorials/testing.md @@ -8,7 +8,7 @@ We will be using typescript to write our tests, and rely on the [`aztec.js`](htt ## A simple example -Let's start with a simple example for a test using the [Sandbox](../cli/sandbox-reference.md). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. +Let's start with a simple example for a test using the [Sandbox](../sandbox/references/sandbox-reference.md). We will create two accounts and deploy a token contract in a setup step, and then issue a transfer from one user to another. #include_code sandbox-example /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript @@ -17,7 +17,7 @@ This test sets up the environment by creating a client to the Private Execution Once we have this setup, the test itself is simple. We check the balance of the `recipient` user to ensure it has no tokens, send and await a deployment transaction, and then check the balance again to ensure it was increased. Note that all numeric values are represented as [native bigints](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) to avoid loss of precision. :::info -We are using the `Token` contract's typescript interface. Follow the [typescript interface section](../contracts/compiling.md#typescript-interfaces) to get type-safe methods for deploying and interacting with the token contract. +We are using the `Token` contract's typescript interface. Follow the [typescript interface section](../contracts/compiling_contracts/how_to_compile_contract.md#typescript-interfaces) to get type-safe methods for deploying and interacting with the token contract. ::: To run the test, first make sure the Sandbox is running on port 8080, and then [run your tests using jest](https://jestjs.io/docs/getting-started#running-from-command-line). Your test should pass, and you should see the following output in the Sandbox logs, where each chunk corresponds to a transaction. Note how this test run has a total of four transactions: two for deploying the account contracts for the `owner` and `recipient`, another for deploying the token contract, and a last one for actually executing the transfer. @@ -148,7 +148,7 @@ In the near future, transactions where a public function call fails will get min 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().view()`. Bear in mind that directly accessing contract storage will break any kind of encapsulation. -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](../contracts/syntax/storage/main.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`](./../testing/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](../contracts/writing_contracts/storage/main.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`](../sandbox/references/cheat_codes.md) utility class: #include_code calc-slot /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript @@ -170,7 +170,7 @@ We can query the Private eXecution Environment (PXE) for all notes encrypted for ### Logs -Last but not least, we can check the logs of [events](../contracts/syntax/events.md) emitted by our contracts. Contracts in Aztec can emit both [encrypted](../contracts/syntax/events.md#encrypted-events) and [unencrypted](../contracts/syntax/events.md#unencrypted-events) events. +Last but not least, we can check the logs of [events](../contracts/writing_contracts/events/emit_event.md) emitted by our contracts. Contracts in Aztec can emit both [encrypted](../contracts/writing_contracts/events/emit_event.md#encrypted-events) and [unencrypted](../contracts/writing_contracts/events/emit_event.md#unencrypted-events) events. :::info At the time of this writing, only unencrypted events can be queried directly. Encrypted events are always assumed to be encrypted notes. @@ -184,7 +184,7 @@ We can query the PXE for the unencrypted logs emitted in the block where our tra ## Cheats -The [`CheatCodes`](./../testing/cheat_codes.md) class, which we used for [calculating the storage slot above](#state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. +The [`CheatCodes`](../sandbox/references/cheat_codes.md) class, which we used for [calculating the storage slot above](#state), also includes a set of cheat methods for modifying the chain state that can be handy for testing. ### Set next block timestamp diff --git a/docs/docs/developers/tutorials/token_portal/main.md b/docs/docs/developers/tutorials/token_portal/main.md index 5739d5b81aa..b4f629f2934 100644 --- a/docs/docs/developers/tutorials/token_portal/main.md +++ b/docs/docs/developers/tutorials/token_portal/main.md @@ -4,7 +4,7 @@ title: Build a Token Bridge import Image from "@theme/IdealImage"; -In this tutorial, we will learn how to build the entire flow of a cross-chain token using portals. If this is your first time hearing the word portal, you’ll want to read [this](../../contracts/portals/main). +In this tutorial, we will learn how to build the entire flow of a cross-chain token using portals. If this is your first time hearing the word portal, you’ll want to read [this](../../../learn/concepts/communication/cross_chain_calls.md). ## A refresher on Portals diff --git a/docs/docs/developers/tutorials/writing_dapp/contract_deployment.md b/docs/docs/developers/tutorials/writing_dapp/contract_deployment.md index b55ebcac2c2..ab3c33912e9 100644 --- a/docs/docs/developers/tutorials/writing_dapp/contract_deployment.md +++ b/docs/docs/developers/tutorials/writing_dapp/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](../../cli/sandbox-reference.md) to install `aztec-nargo` if you haven't done so already. +Follow the instructions [here](../../sandbox/references/sandbox-reference.md) to install `aztec-nargo` if you haven't done so already. ::: ## Initialize Aztec project @@ -35,7 +35,7 @@ The `Token` contract also requires some helper files. You can view the files [he ## Compile your contract -We'll now use `aztec-nargo` to [compile](../../contracts/compiling.md) our project. If you haven't installed aztec-nargo and aztec-cli already, it comes with the sandbox, so you can install it via the [Sandbox install command](../../cli/sandbox-reference.md#installation). +We'll now use `aztec-nargo` to [compile](../../contracts/compiling_contracts/how_to_compile_contract.md) our project. If you haven't installed aztec-nargo and aztec-cli already, it comes with the sandbox, so you can install it via the [Sandbox install command](../../sandbox/references/sandbox-reference.md#installation). Now run the following from your contract folder (containing Nargo.toml): diff --git a/docs/docs/developers/tutorials/writing_dapp/main.md b/docs/docs/developers/tutorials/writing_dapp/main.md index 95cedf910bb..d4fbb7dd0d6 100644 --- a/docs/docs/developers/tutorials/writing_dapp/main.md +++ b/docs/docs/developers/tutorials/writing_dapp/main.md @@ -13,7 +13,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](../../getting_started/quickstart.md) -- [Aztec CLI](../../cli/main.md) +- [Aztec CLI](../../sandbox/main.md) - [Nargo](../../contracts/setup.md) for building contracts ## Prerequisites diff --git a/docs/docs/developers/tutorials/writing_dapp/pxe_service.md b/docs/docs/developers/tutorials/writing_dapp/pxe_service.md index 38a54700c6a..a29ad6971c1 100644 --- a/docs/docs/developers/tutorials/writing_dapp/pxe_service.md +++ b/docs/docs/developers/tutorials/writing_dapp/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](https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/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. -During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](../../cli/sandbox-reference.md), which runs a local PXE and an Aztec Node, both connected to a local Ethereum development node like Anvil. +During the Sandbox phase, this role is fulfilled by the [Aztec Sandbox](../../sandbox/references/sandbox-reference.md), which 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. In this section, we'll connect to the Sandbox from our project. diff --git a/docs/docs/developers/tutorials/writing_dapp/testing.md b/docs/docs/developers/tutorials/writing_dapp/testing.md index 6e835783d3d..51065b0ff87 100644 --- a/docs/docs/developers/tutorials/writing_dapp/testing.md +++ b/docs/docs/developers/tutorials/writing_dapp/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](../../cli/sandbox-reference.md#installation). +We'll need to [install and run the Sandbox](../../sandbox/references/sandbox-reference.md#installation). ## Test setup diff --git a/docs/docs/developers/tutorials/writing_private_voting_contract.md b/docs/docs/developers/tutorials/writing_private_voting_contract.md index 6c107d3ee2d..57efa5c7066 100644 --- a/docs/docs/developers/tutorials/writing_private_voting_contract.md +++ b/docs/docs/developers/tutorials/writing_private_voting_contract.md @@ -131,7 +131,7 @@ Create a private function called `cast_vote`: In this function, we do not create a nullifier with the address directly. This would leak privacy as it would be easy to reverse-engineer. We must add some randomness or some form of secret, like [nullifier secrets](../../learn/concepts/accounts/keys.md#nullifier-secrets). -To do this, we make an [oracle call](../contracts/syntax/functions/oracles.md) to fetch the caller's secret key, hash it to create a nullifier, and push the nullifier to Aztec. The `secret.high` and `secret.low` values here refer to how we divide a large [Grumpkin scalar](https://github.com/AztecProtocol/aztec-packages/blob/7fb35874eae3f2cad5cb922282a619206573592c/noir/noir_stdlib/src/grumpkin_scalar.nr) value into its higher and lower parts. This allows for faster cryptographic computations so our hash can still be secure but is calculated faster. +To do this, we make an [oracle call](../contracts/writing_contracts/oracles/main.md) to fetch the caller's secret key, hash it to create a nullifier, and push the nullifier to Aztec. The `secret.high` and `secret.low` values here refer to how we divide a large [Grumpkin scalar](https://github.com/AztecProtocol/aztec-packages/blob/7fb35874eae3f2cad5cb922282a619206573592c/noir/noir_stdlib/src/grumpkin_scalar.nr) value into its higher and lower parts. This allows for faster cryptographic computations so our hash can still be secure but is calculated faster. After pushing the nullifier, we update the `tally` to reflect this vote. As we know from before, a private function cannot update public state directly, so we are calling a public function. @@ -187,10 +187,10 @@ This will create a new directory called `target` and a JSON artifact inside it. aztec-cli codegen target -o src/artifacts --ts ``` -Once it is compiled you can [deploy](../contracts/deploying.md) it to the sandbox. Ensure your [sandbox is running](../cli/sandbox-reference.md) and run this in the same dir as before: +Once it is compiled you can [deploy](../contracts/deploying_contracts/how_to_deploy_contract.md) it to the sandbox. Ensure your [sandbox is running](../sandbox/references/sandbox-reference.md) and run this in the same dir as before: ```bash -aztec-cli deploy ./target/Voting.json --args $ADMIN_ADDRESS +aztec-cli deploy ./target/private_voting-Voting.json --args $ADMIN_ADDRESS ``` The constructor takes an address as an argument to set the admin, so you can use an address that is deployed with the sandbox - check the sandbox terminal or run `aztec-cli get-accounts`. @@ -200,7 +200,7 @@ You should see a success message with the contract address. Now we can start cal Cast a vote like this: ```bash -aztec-cli send cast_vote --contract-artifact ./target/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 --private-key $PRIVATE_KEY +aztec-cli send cast_vote --contract-artifact ./target/private_voting-Voting.json --contract-address $CONTRACT_ADDRESS --args 1 --private-key $PRIVATE_KEY ``` You can get the contract address from the sandbox terminal or the message printed when you deployed the contract. You can also get a private key from the sandbox terminal, or generate one with `aztec-cli generate-private-key`. @@ -212,12 +212,12 @@ You can now try running this command again to ensure our nullifier works. Get the number of votes like this: ```bash -aztec-cli call get_vote --contract-artifact ./target/Voting.json --contract-address $CONTRACT_ADDRESS --args 1 +aztec-cli call get_vote --contract-artifact ./target/private_voting-Voting.json --contract-address $CONTRACT_ADDRESS --args 1 ``` This should return `1n`. -You can follow this pattern to test `end_vote()` and access control of other functions. Find more information about calling functions from the CLI [here](../cli/cli-commands.md). +You can follow this pattern to test `end_vote()` and access control of other functions. Find more information about calling functions from the CLI [here](../sandbox/references/cli-commands.md). ## Next steps diff --git a/docs/docs/developers/tutorials/writing_token_contract.md b/docs/docs/developers/tutorials/writing_token_contract.md index cde563647ad..fe35268ac32 100644 --- a/docs/docs/developers/tutorials/writing_token_contract.md +++ b/docs/docs/developers/tutorials/writing_token_contract.md @@ -18,7 +18,7 @@ We are going to start with a blank project and fill in the token contract source ## Requirements -You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](../cli/sandbox-reference.md) for installation instructions. +You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](../sandbox/references/sandbox-reference.md) for installation instructions. You should also install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) for VS Code. @@ -223,7 +223,7 @@ The main thing to note from this types folder is the `TransparentNote` definitio ### Note on private state -Private state in Aztec is all [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output) under the hood. Handling UTXOs is largely abstracted away from developers, but there are some unique things for developers to be aware of when creating and managing private state in an Aztec contract. See [State Variables](../contracts/syntax/storage/main.md) to learn more about public and private state in Aztec. +Private state in Aztec is all [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output) under the hood. Handling UTXOs is largely abstracted away from developers, but there are some unique things for developers to be aware of when creating and managing private state in an Aztec contract. See [State Variables](../contracts/writing_contracts/storage/main.md) to learn more about public and private state in Aztec. ## Contract Storage @@ -242,7 +242,7 @@ Reading through the storage variables: - `pending_shields` is a `Set` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. - `public_balances` is a mapping field elements in public state and represents the publicly viewable balances of accounts. -You can read more about it [here](../contracts/syntax/storage/main.md). +You can read more about it [here](../contracts/writing_contracts/storage/main.md). ## Functions @@ -452,7 +452,7 @@ If you don't yet have any private state variables defined put there a placeholde ## Compiling -Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../cli/sandbox-reference.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](../sandbox/references/sandbox-reference.md) for instructions on setting it up. Run the following command in the directory where your `Nargo.toml` file is located: diff --git a/docs/docs/developers/updating.md b/docs/docs/developers/updating.md index 6e9a3b47d57..73eb2549a38 100644 --- a/docs/docs/developers/updating.md +++ b/docs/docs/developers/updating.md @@ -19,7 +19,7 @@ cd your/aztec/project aztec-cli 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](../developers/cli/sandbox-reference.md). +The sandbox must be running for the update command to work. Make sure it is [installed and running](../developers/sandbox/references/sandbox-reference.md). 3. Refer [Migration Notes](../misc/migration_notes.md) on any breaking changes that might affect your dapp diff --git a/docs/docs/developers/wallets/architecture.md b/docs/docs/developers/wallets/architecture.md index 3d010fd3267..bd9d6beeb6d 100644 --- a/docs/docs/developers/wallets/architecture.md +++ b/docs/docs/developers/wallets/architecture.md @@ -1,4 +1,14 @@ -# Architecture +--- +title: Architecture +--- + +This page talks about the architecture of a wallet in Aztec. + +To get an overview about wallets in Aztec, [go here](./main.md). + +To learn how to write an accounts contract, [go here](../contracts/writing_contracts/accounts/write_accounts_contract.md). + +To create a schnorr account in the sandbox, [go here](./creating_schnorr_accounts.md). Wallets expose to dapps an interface that allows them to act on behalf of the user, such as querying private state or sending transactions. Bear mind that, as in Ethereum, wallets should require user confirmation whenever carrying out a potentially sensitive action requested by a dapp. @@ -18,7 +28,7 @@ The account interface is used for creating an _execution request_ out of one or #include_code account-interface yarn-project/aztec.js/src/account/interface.ts typescript -Refer to the page on [writing an account contract](./writing_an_account_contract.md) for an example on how to implement this interface. +Refer to the page on [writing an account contract](../contracts/writing_contracts/accounts/write_accounts_contract.md) for an example on how to implement this interface. ## PXE interface diff --git a/docs/docs/developers/wallets/creating_schnorr_accounts.md b/docs/docs/developers/wallets/creating_schnorr_accounts.md index 636bf8df4af..1ac1443ace6 100644 --- a/docs/docs/developers/wallets/creating_schnorr_accounts.md +++ b/docs/docs/developers/wallets/creating_schnorr_accounts.md @@ -60,4 +60,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](./writing_an_account_contract.md) leveraging our account abstraction +Check out our section on [Writing your own Account Contract](../contracts/writing_contracts/accounts/write_accounts_contract.md) leveraging our account abstraction diff --git a/docs/docs/developers/wallets/main.md b/docs/docs/developers/wallets/main.md index 6e458d8241d..c12288e5478 100644 --- a/docs/docs/developers/wallets/main.md +++ b/docs/docs/developers/wallets/main.md @@ -1,4 +1,12 @@ -# Wallets +--- +title: Wallets +--- + +In this page we will cover the main responsibilities of a wallet in the Aztec network. + +Refer to [_writing an account contract_](../contracts/writing_contracts/accounts/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. Wallets are the applications through which users manage their accounts. Users rely on wallets to browse through their accounts, monitor their balances, and create new accounts. Wallets also store seed phrases and private keys, or interact with external keystores such as hardware wallets. @@ -6,13 +14,11 @@ Wallets also provide an interface for dapps. Dapps may request access to see the In addition to these usual responsibilities, wallets in Aztec also need to track private state. This implies keeping a local database of all private notes encrypted for any of the user's accounts, so dapps and contracts can query the user's private state. Aztec wallets are also responsible for producing local proofs of execution for private functions. -In this page we will cover the main responsibilities of a wallet in the Aztec network. Refer to [_writing an account contract_](./writing_an_account_contract.md) for a tutorial on how to write a contract to back a user's account, or to [_wallet architecture](./architecture.md) for an overview of its architecture and a reference on the interface a wallet must implement. - ## Account setup The first step for any wallet is to let the user set up their [accounts](../../learn/concepts/accounts/main.md). An account in Aztec is represented on-chain by its corresponding account contract that the user must deploy to begin interacting with the network. This account contract dictates how transactions are authenticated and executed. -A wallet must support at least one specific [account contract implementation](./writing_an_account_contract.md), 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). +A wallet must support at least one specific [account contract implementation](../contracts/writing_contracts/accounts/write_accounts_contract.md), 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](../../learn/concepts/accounts/keys.md#addresses-partial-addresses-and-public-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. diff --git a/docs/docs/learn/concepts/accounts/keys.md b/docs/docs/learn/concepts/accounts/keys.md index 5802996cf5e..63cd27b0f3a 100644 --- a/docs/docs/learn/concepts/accounts/keys.md +++ b/docs/docs/learn/concepts/accounts/keys.md @@ -14,7 +14,7 @@ This is a snippet of our Schnorr Account contract implementation, which uses Sch #include_code entrypoint /yarn-project/noir-contracts/contracts/schnorr_account_contract/src/main.nr rust -Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](../../../developers/wallets/writing_an_account_contract.md) for a full example of how to manage authentication. +Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](../../../developers/contracts/writing_contracts/accounts/write_accounts_contract.md) for a full example of how to manage authentication. Furthermore, and since signatures are fully abstracted, how the key is stored in the contract is abstracted as well and left to the developer of the account contract. Here are a few ideas on how to store them, each with their pros and cons. diff --git a/docs/docs/learn/concepts/accounts/main.md b/docs/docs/learn/concepts/accounts/main.md index 3ad58265637..903442f5176 100644 --- a/docs/docs/learn/concepts/accounts/main.md +++ b/docs/docs/learn/concepts/accounts/main.md @@ -1,4 +1,6 @@ -# Accounts +--- +title: Accounts +--- **Every account in Aztec is a smart contract** which defines the rules for whether a transaction is or is not valid. This allows implementing different schemes for transaction signing, nonce management, and fee payments. However, encryption and nullifying keys, which are specific to private blockchains, are still enshrined at the protocol level. @@ -68,7 +70,7 @@ def entryPoint(payload): enqueueCall(to, data, value, gasLimit); ``` -Read more about how to write an account contract [here](../../../developers/wallets/writing_an_account_contract.md). +Read more about how to write an account contract [here](../../../developers/contracts/writing_contracts/accounts/write_accounts_contract.md). ### Account contracts and wallets diff --git a/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md b/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md index a7459932f07..64ced6272fd 100644 --- a/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md +++ b/docs/docs/learn/concepts/communication/public_private_calls/slow_updates_tree.md @@ -70,4 +70,4 @@ Developers are used to instant state updates, so the Slow Updates Tree might tak ## Dive into the code -For a code walkthrough of how a token blacklist contract can use a slow updates tree, read [this](../../../../developers/contracts/syntax/slow_updates_tree.md). \ No newline at end of file +For a code walkthrough of how a token blacklist contract can use a slow updates tree, read [this](../../../../developers/contracts/writing_contracts/historical_data/slow_updates_tree/implement_slow_updates.md). \ No newline at end of file diff --git a/docs/docs/learn/concepts/hybrid_state/main.md b/docs/docs/learn/concepts/hybrid_state/main.md index 2c540f2a077..20493fab3d0 100644 --- a/docs/docs/learn/concepts/hybrid_state/main.md +++ b/docs/docs/learn/concepts/hybrid_state/main.md @@ -43,4 +43,4 @@ This is achieved with two main features: ## Further reading -Read more about how to leverage the Aztec state model in Aztec contracts [here](../../../developers/contracts/syntax/storage/main.md). +Read more about how to leverage the Aztec state model in Aztec contracts [here](../../../developers/contracts/writing_contracts/storage/main.md). diff --git a/docs/docs/learn/concepts/pxe/acir_simulator.md b/docs/docs/learn/concepts/pxe/acir_simulator.md index 0b794773205..3927f094e2a 100644 --- a/docs/docs/learn/concepts/pxe/acir_simulator.md +++ b/docs/docs/learn/concepts/pxe/acir_simulator.md @@ -14,7 +14,7 @@ It simulates three types of functions: Private functions are simulated and proved client-side, and verified client-side in the private kernel circuit. -They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](../../../developers/contracts/syntax/functions/oracles.md). +They are run with the assistance of a DB oracle that provides any private data requested by the function. You can read more about oracle functions in the smart contract section [here](../../../developers/contracts/writing_contracts/oracles/main.md). Private functions can call other private functions and can request to call a public function. The public function execution will be performed by the sequencer asynchronously, so private functions don't have direct access to the return values of public functions. diff --git a/docs/docs/learn/concepts/pxe/main.md b/docs/docs/learn/concepts/pxe/main.md index 028aaf12081..25993ced214 100644 --- a/docs/docs/learn/concepts/pxe/main.md +++ b/docs/docs/learn/concepts/pxe/main.md @@ -62,9 +62,9 @@ The keystore is a secure storage for private and public keys. ## Oracles -Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](../../../developers/contracts/syntax/functions/oracles.md). +Oracles are pieces of data that are injected into a smart contract function from the client side. You can read more about why and how they work in the [functions section](../../../developers/contracts/writing_contracts/oracles/main.md). ## For developers To learn how to develop on top of the PXE, refer to these guides: -* [Run more than one PXE on your local machine](../../../developers/cli/run_more_than_one_pxe_sandbox.md) -* [Use in-built oracles including oracles for arbitrary data](../../../developers/contracts/syntax/oracles.md) \ No newline at end of file +* [Run more than one PXE on your local machine](../../../developers/sandbox/guides/run_more_than_one_pxe_sandbox.md) +* [Use in-built oracles including oracles for arbitrary data](../../../developers/contracts/writing_contracts/oracles/pop_capsule.md) \ No newline at end of file diff --git a/docs/docs/learn/concepts/storage/storage_slots.md b/docs/docs/learn/concepts/storage/storage_slots.md index 80013ecd156..3aff76c895d 100644 --- a/docs/docs/learn/concepts/storage/storage_slots.md +++ b/docs/docs/learn/concepts/storage/storage_slots.md @@ -62,4 +62,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 storage slots](./../../../developers/contracts/syntax/storage/storage_slots.md). +For an example of this see [developer documentation storage slots](../../../developers/contracts/writing_contracts/storage/main.md). diff --git a/docs/docs/learn/concepts/storage/trees/main.md b/docs/docs/learn/concepts/storage/trees/main.md index af58086e10f..672e3b0aac0 100644 --- a/docs/docs/learn/concepts/storage/trees/main.md +++ b/docs/docs/learn/concepts/storage/trees/main.md @@ -211,7 +211,7 @@ HistoricalAccessTree --- Header ``` -It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](../../../../developers/contracts/syntax/historical_access/how_to_prove_history.md). +It can also be used to find information about notes, public state, and contracts that were included in a certain block using [inclusion and non-inclusion proofs](../../../../developers/contracts/writing_contracts/historical_data/archive_tree/how_to_prove_history.md). ## Trees of valid Kernel/Rollup circuit Verification Keys diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 0c6533a34ea..035a838141b 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,7 +6,7 @@ keywords: [sandbox, cli, 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 +## 0.22.0 ### `Note::compute_note_hash` renamed to `Note::compute_note_content_hash` The `compute_note_hash` function in of the `Note` trait has been renamed to `compute_note_content_hash` to avoid being confused with the actual note hash. @@ -38,10 +38,48 @@ Makes a split in logic for note hash computation for consumption and insertion. `compute_note_hash_for_consumption` replaces `compute_note_hash_for_read_or_nullify`. `compute_note_hash_for_insertion` is new, and mainly used in `lifecycle.nr`` +### `Note::serialize_content` and `Note::deserialize_content` added to `NoteInterface -## 0.22.0 +The `NoteInterface` have been extended to include `serialize_content` and `deserialize_content` functions. This is to convey the difference between serializing the full note, and just the content. This change allows you to also add a `serialize` function to support passing in a complete note to a function. + +Before: +```rust +impl Serialize for AddressNote { + fn serialize(self) -> [Field; ADDRESS_NOTE_LEN]{ + [self.address.to_field(), self.owner.to_field(), self.randomness] + } +} +impl Deserialize for AddressNote { + fn deserialize(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { + AddressNote { + address: AztecAddress::from_field(serialized_note[0]), + owner: AztecAddress::from_field(serialized_note[1]), + randomness: serialized_note[2], + header: NoteHeader::empty(), + } + } +``` + +Now +```rust +impl NoteInterface for AddressNote { + fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ + [self.address.to_field(), self.owner.to_field(), self.randomness] + } + + fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { + AddressNote { + address: AztecAddress::from_field(serialized_note[0]), + owner: AztecAddress::from_field(serialized_note[1]), + randomness: serialized_note[2], + header: NoteHeader::empty(), + } + } + ... +} +``` -### [Aztec.nr] `Serialize`, `Deserialize`, `NoteInterface` as Traits, removal of SerializationMethods and SERIALIZED_LEN +### [Aztec.nr] No storage.init() and `Serialize`, `Deserialize`, `NoteInterface` as Traits, removal of SerializationMethods and SERIALIZED_LEN Storage definition and initialization has been simplified. Previously: diff --git a/docs/netlify.toml b/docs/netlify.toml index 029b6ad77e3..adb1929ab8e 100644 --- a/docs/netlify.toml +++ b/docs/netlify.toml @@ -162,6 +162,10 @@ from = "/aztec/protocol/contract-creation" to = "/learn/concepts/contracts/contract_creation" +[[redirects]] + from = "/concepts/advanced/contract_creation" + to = "/learn/concepts/smart_contracts/main" + [[redirects]] from = "/noir" to = "/" @@ -208,4 +212,4 @@ [[redirects]] from= "zk-money/userguide" - to= "/misc/aztec_connect_sunset" \ No newline at end of file + to= "/misc/aztec_connect_sunset" diff --git a/docs/sidebars.js b/docs/sidebars.js index 88dc7f7bd73..a779fdf94ac 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -22,7 +22,7 @@ const sidebars = { // ABOUT AZTEC { - type: "html", + type: "html", className: "sidebar-title", value: "LEARN", defaultStyle: true, @@ -254,93 +254,194 @@ const sidebars = { type: "category", link: { type: "doc", - id: "developers/cli/main", + id: "developers/sandbox/main", }, items: [ - "developers/cli/cli-commands", - "developers/cli/sandbox-reference", - "developers/cli/run_more_than_one_pxe_sandbox", + { + label: "Guides", + type: "category", + items: [ + "developers/sandbox/guides/blank_box", + "developers/sandbox/guides/run_more_than_one_pxe_sandbox", + "developers/wallets/creating_schnorr_accounts", + ], + }, + { + label: "References", + type: "category", + items: [ + "developers/sandbox/references/cli-commands", + "developers/sandbox/references/sandbox-reference", + "developers/sandbox/references/cheat_codes", + { + label: "PXE Reference", + type: "doc", + id: "apis/pxe/interfaces/PXE", + }, + ], + + }, + ], }, { - label: "Aztec.nr Contracts", + label: "Smart Contracts", type: "category", link: { type: "doc", id: "developers/contracts/main", }, items: [ - "developers/contracts/workflow", "developers/contracts/setup", - "developers/contracts/layout", { - label: "Syntax", + label: "Writing Contracts", type: "category", - link: { - type: "doc", - id: "developers/contracts/syntax/main", - }, items: [ + "developers/contracts/writing_contracts/layout", + "developers/contracts/writing_contracts/example_contract", + { + label: "Functions and Constructors", + type: "category", + link: { + type: "doc", + id: "developers/contracts/writing_contracts/functions/main", + }, + items: [ + "developers/contracts/writing_contracts/functions/context", + "developers/contracts/writing_contracts/functions/public_private_unconstrained", + "developers/contracts/writing_contracts/functions/visibility", + "developers/contracts/writing_contracts/functions/call_functions", + "developers/contracts/writing_contracts/functions/write_constructor", + "developers/contracts/writing_contracts/functions/inner_workings", + ], + }, { label: "Storage", type: "category", link: { type: "doc", - id: "developers/contracts/syntax/storage/main", + id: "developers/contracts/writing_contracts/storage/main", + }, + items: [ + "developers/contracts/writing_contracts/storage/define_storage", + "developers/contracts/writing_contracts/storage/storage_slots", + ], + }, + { + label: "Accounts and Account Contracts", + type: "category", + items: [ + "developers/contracts/writing_contracts/accounts/write_accounts_contract", + + ], + }, + { + label: "Events", + type: "category", + items: [ + "developers/contracts/writing_contracts/events/emit_event", + ], + }, + { + label: "Oracles", + type: "category", + link: { + type: "doc", + id: "developers/contracts/writing_contracts/oracles/main", }, items: [ - "developers/contracts/syntax/storage/private_state", - "developers/contracts/syntax/storage/public_state", - "developers/contracts/syntax/storage/storage_slots", + "developers/contracts/writing_contracts/oracles/inbuilt_oracles", + "developers/contracts/writing_contracts/oracles/pop_capsule", ], }, - "developers/contracts/syntax/events", { - label: "Functions", + label: "Portals", type: "category", link: { type: "doc", - id: "developers/contracts/syntax/functions/main", + id: "developers/contracts/writing_contracts/portals/portals", }, items: [ - "developers/contracts/syntax/functions/public_private_unconstrained", - "developers/contracts/syntax/functions/visibility", - "developers/contracts/syntax/functions/constructor", - "developers/contracts/syntax/functions/calling_functions", - "developers/contracts/syntax/functions/oracles", - "developers/contracts/syntax/functions/inner_workings", + "developers/contracts/writing_contracts/portals/deploy_with_portal", + "developers/contracts/writing_contracts/portals/communicate_with_portal", ], }, - "developers/contracts/syntax/oracles", { - label: "Proving Historical Blockchain Data", + label: "Historical Data", type: "category", items: [ - "developers/contracts/syntax/historical_access/how_to_prove_history", - "developers/contracts/syntax/historical_access/history_lib_reference", + { + label: "Historical Blockchain Data (Archive Tree)", + type: "category", + link: { + type: "doc", + id: "developers/contracts/writing_contracts/historical_data/slow_updates_tree/main", + }, + items: [ + "developers/contracts/writing_contracts/historical_data/archive_tree/how_to_prove_history", + ], + }, ], }, - "developers/contracts/syntax/slow_updates_tree", - - "developers/contracts/syntax/context", - "developers/contracts/syntax/globals", + { + label: "Access public data from private state (Slow Updates Tree)", + type: "category", + link: { + type: "doc", + id: "developers/contracts/writing_contracts/historical_data/slow_updates_tree/main", + }, + items: [ + "developers/contracts/writing_contracts/historical_data/slow_updates_tree/implement_slow_updates", + ], + }, + ], }, - "developers/contracts/compiling", - "developers/contracts/deploying", - "developers/contracts/artifacts", { - label: "Portals", + label: "Compiling Contracts", type: "category", - link: { - type: "doc", - id: "developers/contracts/portals/main", - }, items: [ - "developers/contracts/portals/data_structures", - "developers/contracts/portals/registry", - "developers/contracts/portals/inbox", - "developers/contracts/portals/outbox", + "developers/contracts/compiling_contracts/how_to_compile_contract", + "developers/contracts/compiling_contracts/artifacts", + ], + }, + { + label: "Deploying Contracts", + type: "category", + items: [ + "developers/contracts/deploying_contracts/how_to_deploy_contract", + ], + }, + "developers/contracts/testing_contracts/main", + { + label: "References", + type: "category", + items: [ + "developers/contracts/references/globals", + { + label: "Storage Reference", + type: "category", + link: { + type: "doc", + id: "developers/contracts/references/storage/main", + }, + items: [ + "developers/contracts/references/storage/private_state", + "developers/contracts/references/storage/public_state" + ], + }, + { + label: "Portals Reference", + type: "category", + items: [ + "developers/contracts/references/portals/data_structures", + "developers/contracts/references/portals/inbox", + "developers/contracts/references/portals/outbox", + "developers/contracts/references/portals/registry", + ], + }, + "developers/contracts/references/history_lib_reference", + "developers/contracts/references/slow_updates_tree", ], }, { @@ -386,8 +487,39 @@ const sidebars = { { label: "Aztec.js", - type: "doc", - id: "developers/aztecjs/main", + type: "category", + link: { + type: "doc", + id: "developers/aztecjs/main", + }, + items: [ + { + label: "Guides", + type: "category", + items: [ + "developers/aztecjs/guides/create_account", + "developers/aztecjs/guides/deploy_contract", + "developers/aztecjs/guides/send_transaction", + "developers/aztecjs/guides/call_view_function", + ], + }, + { + label: "References", + type: "category", + items: [ + { + label: "Aztec.js", + type: "category", + items: [{ dirName: "apis/aztec-js", type: "autogenerated" }], + }, + { + label: "Accounts", + type: "category", + items: [{ dirName: "apis/accounts", type: "autogenerated" }], + }, + ], + }, + ], }, { label: "Debugging", @@ -406,16 +538,6 @@ const sidebars = { type: "doc", id: "developers/updating", }, - - { - label: "Testing", - type: "category", - link: { - type: "doc", - id: "developers/testing/main", - }, - items: ["developers/testing/cheat_codes"], - }, { label: "Wallets", type: "category", @@ -425,8 +547,6 @@ const sidebars = { }, items: [ "developers/wallets/architecture", - "developers/wallets/writing_an_account_contract", - "developers/wallets/creating_schnorr_accounts", ], }, @@ -438,28 +558,6 @@ const sidebars = { "developers/privacy/main", "developers/limitations/main", - { - label: "API Reference", - type: "category", - items: [ - { - label: "Private Execution Environment (PXE)", - type: "doc", - id: "apis/pxe/interfaces/PXE", - }, - { - label: "Aztec.js", - type: "category", - items: [{ dirName: "apis/aztec-js", type: "autogenerated" }], - }, - { - label: "Accounts", - type: "category", - items: [{ dirName: "apis/accounts", type: "autogenerated" }], - }, - ], - }, - { type: "html", value: '', diff --git a/docs/static/img/com-abs-1.png b/docs/static/img/com-abs-1.png index 6f664a13274..a3d5219072c 100644 Binary files a/docs/static/img/com-abs-1.png and b/docs/static/img/com-abs-1.png differ diff --git a/docs/static/img/com-abs-2.png b/docs/static/img/com-abs-2.png index 45567cbd512..f512d999915 100644 Binary files a/docs/static/img/com-abs-2.png and b/docs/static/img/com-abs-2.png differ diff --git a/docs/static/img/com-abs-3.png b/docs/static/img/com-abs-3.png index 247b9693226..47ba78f9d73 100644 Binary files a/docs/static/img/com-abs-3.png and b/docs/static/img/com-abs-3.png differ diff --git a/docs/static/img/com-abs-4.png b/docs/static/img/com-abs-4.png index 37254ecd22d..778d6281589 100644 Binary files a/docs/static/img/com-abs-4.png and b/docs/static/img/com-abs-4.png differ diff --git a/docs/static/img/com-abs-5.png b/docs/static/img/com-abs-5.png index 1483861c88d..c672d331b51 100644 Binary files a/docs/static/img/com-abs-5.png and b/docs/static/img/com-abs-5.png differ diff --git a/docs/static/img/com-abs-6.png b/docs/static/img/com-abs-6.png index 20ec6779ef0..421933ac7de 100644 Binary files a/docs/static/img/com-abs-6.png and b/docs/static/img/com-abs-6.png differ diff --git a/docs/static/img/com-abs-7.png b/docs/static/img/com-abs-7.png index 6fa4a1d0c24..5aa75171f50 100644 Binary files a/docs/static/img/com-abs-7.png and b/docs/static/img/com-abs-7.png differ diff --git a/l1-contracts/package.json b/l1-contracts/package.json index 006ddcd0228..52841e0aa30 100644 --- a/l1-contracts/package.json +++ b/l1-contracts/package.json @@ -7,6 +7,7 @@ "solhint": "https://github.com/LHerskind/solhint#master" }, "scripts": { + "format": "./.foundry/bin/forge fmt", "lint": "solhint --config ./.solhint.json --fix \"src/**/*.sol\"", "slither": "forge clean && forge build --build-info --skip '*/test/**' --force && slither . --checklist --ignore-compile --show-ignored-findings --config-file ./slither.config.json | tee slither_output.md", "slither-has-diff": "./slither_has_diff.sh" diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index db4b5b391fd..c7e0d6024fd 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -5,15 +5,15 @@ Summary - [pess-dubious-typecast](#pess-dubious-typecast) (8 results) (Medium) - [reentrancy-events](#reentrancy-events) (1 results) (Low) - [timestamp](#timestamp) (4 results) (Low) - - [pess-public-vs-external](#pess-public-vs-external) (4 results) (Low) + - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) - [assembly](#assembly) (5 results) (Informational) - [dead-code](#dead-code) (13 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [low-level-calls](#low-level-calls) (1 results) (Informational) - [similar-names](#similar-names) (1 results) (Informational) - [unused-state](#unused-state) (2 results) (Informational) - - [pess-magic-number](#pess-magic-number) (1 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) + - [pess-multiple-storage-read](#pess-multiple-storage-read) (2 results) (Optimization) ## pess-unprotected-setter Impact: High Confidence: Medium @@ -27,9 +27,9 @@ src/core/Rollup.sol#L54-L94 Impact: Medium Confidence: Medium - [ ] ID-1 -[HeaderLib.decode(bytes).header](src/core/libraries/HeaderLib.sol#L133) is a local variable never initialized +[HeaderLib.decode(bytes).header](src/core/libraries/HeaderLib.sol#L139) is a local variable never initialized -src/core/libraries/HeaderLib.sol#L133 +src/core/libraries/HeaderLib.sol#L139 ## unused-return @@ -59,13 +59,38 @@ src/core/libraries/decoders/Decoder.sol#L415-L417 - [ ] ID-5 +Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L134-L175): + bytes => bytes32 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L142-L144) + bytes => bytes4 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L142-L144) + bytes => bytes32 casting occurs in [header.bodyHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L147) + bytes => bytes32 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L150-L152) + bytes => bytes4 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L150-L152) + bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) + bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) + bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L156-L158) + bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L156-L158) + bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.contractTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L159-L161) + bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.contractTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L159-L161) + bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L162-L164) + bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L162-L164) + bytes => bytes32 casting occurs in [header.globalVariables.chainId = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L167) + bytes => bytes32 casting occurs in [header.globalVariables.version = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L168) + bytes => bytes32 casting occurs in [header.globalVariables.blockNumber = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L169) + bytes => bytes32 casting occurs in [header.globalVariables.timestamp = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L170) + bytes => bytes20 casting occurs in [header.globalVariables.coinbase = address(bytes20(_header))](src/core/libraries/HeaderLib.sol#L171) + bytes => bytes32 casting occurs in [header.globalVariables.feeRecipient = bytes32(_header)](src/core/libraries/HeaderLib.sol#L172) + +src/core/libraries/HeaderLib.sol#L134-L175 + + + - [ ] ID-6 Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) src/core/messagebridge/Outbox.sol#L38-L46 - - [ ] ID-6 + - [ ] ID-7 Dubious typecast in [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91): uint256 => uint64 casting occurs in [fee = uint64(msg.value)](src/core/messagebridge/Inbox.sol#L64) uint256 => uint32 casting occurs in [entries.insert(key,fee,uint32(_recipient.version),_deadline,_errIncompatibleEntryArguments)](src/core/messagebridge/Inbox.sol#L76) @@ -73,29 +98,6 @@ Dubious typecast in [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,b src/core/messagebridge/Inbox.sol#L45-L91 - - [ ] ID-7 -Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L128-L167): - bytes => bytes32 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L136-L138) - bytes => bytes4 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L136-L138) - bytes => bytes32 casting occurs in [header.bodyHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L141) - bytes => bytes32 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L144-L146) - bytes => bytes4 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L144-L146) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L147-L149) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L147-L149) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L150-L152) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L150-L152) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.contractTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.contractTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L156-L158) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L156-L158) - bytes => bytes32 casting occurs in [header.globalVariables.chainId = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L161) - bytes => bytes32 casting occurs in [header.globalVariables.version = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L162) - bytes => bytes32 casting occurs in [header.globalVariables.blockNumber = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L163) - bytes => bytes32 casting occurs in [header.globalVariables.timestamp = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L164) - -src/core/libraries/HeaderLib.sol#L128-L167 - - - [ ] ID-8 Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L110-L112): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L111) @@ -151,11 +153,11 @@ src/core/messagebridge/Inbox.sol#L45-L91 - [ ] ID-14 -[HeaderLib.validate(HeaderLib.Header,uint256,uint256,bytes32)](src/core/libraries/HeaderLib.sol#L91-L121) uses timestamp for comparisons +[HeaderLib.validate(HeaderLib.Header,uint256,uint256,bytes32)](src/core/libraries/HeaderLib.sol#L97-L127) uses timestamp for comparisons Dangerous comparisons: - - [_header.globalVariables.timestamp > block.timestamp](src/core/libraries/HeaderLib.sol#L105) + - [_header.globalVariables.timestamp > block.timestamp](src/core/libraries/HeaderLib.sol#L111) -src/core/libraries/HeaderLib.sol#L91-L121 +src/core/libraries/HeaderLib.sol#L97-L127 - [ ] ID-15 @@ -170,20 +172,27 @@ src/core/messagebridge/Inbox.sol#L102-L113 Impact: Low Confidence: Medium - [ ] ID-16 +The following public functions could be turned into external in [FrontierMerkle](src/core/messagebridge/frontier_tree/Frontier.sol#L7-L85) contract: + [FrontierMerkle.constructor(uint256)](src/core/messagebridge/frontier_tree/Frontier.sol#L19-L27) + +src/core/messagebridge/frontier_tree/Frontier.sol#L7-L85 + + + - [ ] ID-17 The following public functions could be turned into external in [Registry](src/core/messagebridge/Registry.sol#L22-L129) contract: [Registry.constructor()](src/core/messagebridge/Registry.sol#L29-L33) src/core/messagebridge/Registry.sol#L22-L129 - - [ ] ID-17 + - [ ] ID-18 The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L27-L103) contract: [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L39-L44) src/core/Rollup.sol#L27-L103 - - [ ] ID-18 + - [ ] ID-19 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L149) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L78-L85) @@ -192,7 +201,7 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L149 - - [ ] ID-19 + - [ ] ID-20 The following public functions could be turned into external in [Inbox](src/core/messagebridge/Inbox.sol#L21-L231) contract: [Inbox.constructor(address)](src/core/messagebridge/Inbox.sol#L30-L32) [Inbox.contains(bytes32)](src/core/messagebridge/Inbox.sol#L174-L176) @@ -203,21 +212,21 @@ src/core/messagebridge/Inbox.sol#L21-L231 ## assembly Impact: Informational Confidence: High - - [ ] ID-20 + - [ ] ID-21 [Decoder.computeRoot(bytes32[])](src/core/libraries/decoders/Decoder.sol#L373-L392) uses assembly - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L380-L382) src/core/libraries/decoders/Decoder.sol#L373-L392 - - [ ] ID-21 + - [ ] ID-22 [TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L71-L184) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L98-L104) src/core/libraries/decoders/TxsDecoder.sol#L71-L184 - - [ ] ID-22 + - [ ] ID-23 [Decoder.computeConsumables(bytes)](src/core/libraries/decoders/Decoder.sol#L164-L301) uses assembly - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L196-L202) - [INLINE ASM](src/core/libraries/decoders/Decoder.sol#L289-L295) @@ -225,14 +234,14 @@ src/core/libraries/decoders/TxsDecoder.sol#L71-L184 src/core/libraries/decoders/Decoder.sol#L164-L301 - - [ ] ID-23 + - [ ] ID-24 [TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L256-L275) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L263-L265) src/core/libraries/decoders/TxsDecoder.sol#L256-L275 - - [ ] ID-24 + - [ ] ID-25 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L52-L102) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L81-L83) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L94-L96) @@ -243,79 +252,79 @@ src/core/libraries/decoders/MessagesDecoder.sol#L52-L102 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-25 + - [ ] ID-26 [Decoder.computeConsumables(bytes)](src/core/libraries/decoders/Decoder.sol#L164-L301) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L164-L301 - - [ ] ID-26 + - [ ] ID-27 [Inbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Inbox.sol#L212-L230) is never used and should be removed src/core/messagebridge/Inbox.sol#L212-L230 - - [ ] ID-27 + - [ ] ID-28 [Decoder.slice(bytes,uint256,uint256)](src/core/libraries/decoders/Decoder.sol#L401-L407) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L401-L407 - - [ ] ID-28 + - [ ] ID-29 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L115-L117) is never used and should be removed src/core/messagebridge/Outbox.sol#L115-L117 - - [ ] ID-29 + - [ ] ID-30 [Decoder.computeRoot(bytes32[])](src/core/libraries/decoders/Decoder.sol#L373-L392) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L373-L392 - - [ ] ID-30 + - [ ] ID-31 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L59-L61) is never used and should be removed src/core/libraries/Hash.sol#L59-L61 - - [ ] ID-31 + - [ ] ID-32 [Decoder.computeKernelLogsHash(uint256,bytes)](src/core/libraries/decoders/Decoder.sol#L335-L365) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L335-L365 - - [ ] ID-32 + - [ ] ID-33 [Decoder.read4(bytes,uint256)](src/core/libraries/decoders/Decoder.sol#L415-L417) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L415-L417 - - [ ] ID-33 + - [ ] ID-34 [Decoder.computeStateHash(uint256,uint256,bytes)](src/core/libraries/decoders/Decoder.sol#L146-L154) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L146-L154 - - [ ] ID-34 + - [ ] ID-35 [Decoder.computePublicInputHash(bytes,bytes32,bytes32)](src/core/libraries/decoders/Decoder.sol#L118-L125) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L118-L125 - - [ ] ID-35 + - [ ] ID-36 [Inbox._errNothingToConsume(bytes32)](src/core/messagebridge/Inbox.sol#L197-L199) is never used and should be removed src/core/messagebridge/Inbox.sol#L197-L199 - - [ ] ID-36 + - [ ] ID-37 [Decoder.getL2BlockNumber(bytes)](src/core/libraries/decoders/Decoder.sol#L132-L134) is never used and should be removed src/core/libraries/decoders/Decoder.sol#L132-L134 - - [ ] ID-37 + - [ ] ID-38 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L130-L148) is never used and should be removed src/core/messagebridge/Outbox.sol#L130-L148 @@ -324,13 +333,13 @@ src/core/messagebridge/Outbox.sol#L130-L148 ## solc-version Impact: Informational Confidence: High - - [ ] ID-38 + - [ ] ID-39 solc-0.8.21 is not recommended for deployment ## low-level-calls Impact: Informational Confidence: High - - [ ] ID-39 + - [ ] ID-40 Low level call in [Inbox.withdrawFees()](src/core/messagebridge/Inbox.sol#L148-L153): - [(success) = msg.sender.call{value: balance}()](src/core/messagebridge/Inbox.sol#L151) @@ -340,7 +349,7 @@ src/core/messagebridge/Inbox.sol#L148-L153 ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-40 + - [ ] ID-41 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L30) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L39) src/core/Rollup.sol#L30 @@ -349,29 +358,18 @@ src/core/Rollup.sol#L30 ## unused-state Impact: Informational Confidence: High - - [ ] ID-41 + - [ ] ID-42 [Decoder.END_TREES_BLOCK_HEADER_OFFSET](src/core/libraries/decoders/Decoder.sol#L103-L104) is never used in [Decoder](src/core/libraries/decoders/Decoder.sol#L72-L418) src/core/libraries/decoders/Decoder.sol#L103-L104 - - [ ] ID-42 + - [ ] ID-43 [Decoder.BLOCK_HEADER_OFFSET](src/core/libraries/decoders/Decoder.sol#L107-L108) is never used in [Decoder](src/core/libraries/decoders/Decoder.sol#L72-L418) src/core/libraries/decoders/Decoder.sol#L107-L108 -## pess-magic-number -Impact: Informational -Confidence: High - - [ ] ID-43 -Magic number 376 is used multiple times in: - [_header.length != 376](src/core/libraries/HeaderLib.sol#L129) - [Errors.HeaderLib__InvalidHeaderSize(376,_header.length)](src/core/libraries/HeaderLib.sol#L130) - -src/core/libraries/HeaderLib.sol#L129 - - ## constable-states Impact: Optimization Confidence: High @@ -381,3 +379,18 @@ Confidence: High src/core/Rollup.sol#L37 +## pess-multiple-storage-read +Impact: Optimization +Confidence: High + - [ ] ID-45 +In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72) variable [FrontierMerkle.DEPTH](src/core/messagebridge/frontier_tree/Frontier.sol#L8) is read multiple times + +src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72 + + + - [ ] ID-46 +In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72) variable [FrontierMerkle.frontier](src/core/messagebridge/frontier_tree/Frontier.sol#L13) is read multiple times + +src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72 + + diff --git a/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol b/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol new file mode 100644 index 00000000000..5b17cab8dc4 --- /dev/null +++ b/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +interface IFrontier { + function insertLeaf(bytes32 _leaf) external; + + function root() external view returns (bytes32); +} diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 68465421abd..3a0da1d4d75 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -33,11 +33,13 @@ library Constants { uint256 internal constant MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; uint256 internal constant MAX_PUBLIC_DATA_READS_PER_TX = 16; uint256 internal constant MAX_NEW_CONTRACTS_PER_TX = 1; - uint256 internal constant MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX = 4; uint256 internal constant MAX_READ_REQUESTS_PER_TX = 128; uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; uint256 internal constant NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; + uint256 internal constant MAX_NEW_COMMITMENTS_PER_TX_META = 8; + uint256 internal constant MAX_NEW_NULLIFIERS_PER_TX_META = 8; + uint256 internal constant MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META = 2; uint256 internal constant NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; uint256 internal constant VK_TREE_HEIGHT = 3; uint256 internal constant FUNCTION_TREE_HEIGHT = 5; @@ -47,6 +49,7 @@ library Constants { uint256 internal constant NULLIFIER_TREE_HEIGHT = 20; uint256 internal constant L1_TO_L2_MSG_TREE_HEIGHT = 16; uint256 internal constant ROLLUP_VK_TREE_HEIGHT = 8; + uint256 internal constant ARTIFACT_FUNCTION_TREE_MAX_HEIGHT = 5; uint256 internal constant CONTRACT_SUBTREE_HEIGHT = 0; uint256 internal constant CONTRACT_SUBTREE_SIBLING_PATH_LENGTH = 16; uint256 internal constant NOTE_HASH_SUBTREE_HEIGHT = 6; @@ -62,7 +65,18 @@ library Constants { uint256 internal constant MAPPING_SLOT_PEDERSEN_SEPARATOR = 4; uint256 internal constant NUM_FIELDS_PER_SHA256 = 2; uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 32; - uint256 internal constant ARGS_HASH_CHUNK_COUNT = 16; + uint256 internal constant ARGS_HASH_CHUNK_COUNT = 32; + uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 1000; + uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; + uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; + uint256 internal constant REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = + 0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8; + uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = + 0x1b70e95fde0b70adc30496b90a327af6a5e383e028e7a43211a07bcd; + uint256 internal constant REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = + 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99; + uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = + 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 8; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; @@ -70,18 +84,18 @@ library Constants { uint256 internal constant MAX_NOTES_PER_PAGE = 10; uint256 internal constant VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; uint256 internal constant CALL_CONTEXT_LENGTH = 8; - uint256 internal constant GLOBAL_VARIABLES_LENGTH = 4; + uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6; uint256 internal constant PARTIAL_STATE_REFERENCE_LENGTH = 8; uint256 internal constant STATE_REFERENCE_LENGTH = 10; - uint256 internal constant HEADER_LENGTH = 18; + uint256 internal constant HEADER_LENGTH = 20; uint256 internal constant FUNCTION_DATA_LENGTH = 4; uint256 internal constant CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 204; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 207; + uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 212; uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; - uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 201; + uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 203; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; - uint256 internal constant CALL_PRIVATE_FUNCTION_RETURN_SIZE = 210; uint256 internal constant COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 1024; diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index f588c7c1d4d..14be2064f07 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -54,7 +54,7 @@ library DataStructures { * @param sender - The sender of the message * @param recipient - The recipient of the message * @param content - The content of the message (application specific) padded to bytes32 or hashed if larger. - * @param secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2) + * @param secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2). * @param deadline - The deadline to consume a message. Only after it, can a message be cancelled. * @param fee - The fee provided to sequencer for including the entry */ diff --git a/l1-contracts/src/core/libraries/HeaderLib.sol b/l1-contracts/src/core/libraries/HeaderLib.sol index 5ea03ee283c..6c76bacbc28 100644 --- a/l1-contracts/src/core/libraries/HeaderLib.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -44,6 +44,8 @@ import {Hash} from "./Hash.sol"; * | 0x0118 | 0x20 | version * | 0x0138 | 0x20 | blockNumber * | 0x0158 | 0x20 | timestamp + * | 0x0178 | 0x14 | coinbase + * | 0x018c | 0x20 | feeRecipient * | | | } * | | | } * | --- | --- | --- @@ -72,6 +74,8 @@ library HeaderLib { uint256 version; uint256 blockNumber; uint256 timestamp; + address coinbase; + bytes32 feeRecipient; } struct Header { @@ -81,6 +85,8 @@ library HeaderLib { GlobalVariables globalVariables; } + uint256 private constant HEADER_LENGTH = 0x1ac; // Header byte length + /** * @notice Validates the header * @param _header - The decoded header @@ -126,8 +132,8 @@ library HeaderLib { * @return The decoded header */ function decode(bytes calldata _header) internal pure returns (Header memory) { - if (_header.length != 376) { - revert Errors.HeaderLib__InvalidHeaderSize(376, _header.length); + if (_header.length != HEADER_LENGTH) { + revert Errors.HeaderLib__InvalidHeaderSize(HEADER_LENGTH, _header.length); } Header memory header; @@ -162,6 +168,8 @@ library HeaderLib { header.globalVariables.version = uint256(bytes32(_header[0x0118:0x0138])); header.globalVariables.blockNumber = uint256(bytes32(_header[0x0138:0x0158])); header.globalVariables.timestamp = uint256(bytes32(_header[0x0158:0x0178])); + header.globalVariables.coinbase = address(bytes20(_header[0x0178:0x018c])); + header.globalVariables.feeRecipient = bytes32(_header[0x018c:HEADER_LENGTH]); return header; } diff --git a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol new file mode 100644 index 00000000000..d20e053a58c --- /dev/null +++ b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {IFrontier} from "../../interfaces/messagebridge/IFrontier.sol"; + +contract FrontierMerkle is IFrontier { + uint256 public immutable DEPTH; + uint256 public immutable SIZE; + + uint256 internal nextIndex = 0; + + mapping(uint256 level => bytes32 node) public frontier; + + // Below can be pre-computed so it would be possible to have constants + // for the zeros at each level. This would save gas on computations + mapping(uint256 level => bytes32 zero) public zeros; + + constructor(uint256 _depth) { + DEPTH = _depth; + SIZE = 2 ** _depth; + + zeros[0] = bytes32(0); + for (uint256 i = 1; i <= DEPTH; i++) { + zeros[i] = sha256(bytes.concat(zeros[i - 1], zeros[i - 1])); + } + } + + function insertLeaf(bytes32 _leaf) external override(IFrontier) { + uint256 level = _computeLevel(nextIndex); + bytes32 right = _leaf; + for (uint256 i = 0; i < level; i++) { + right = sha256(bytes.concat(frontier[i], right)); + } + frontier[level] = right; + nextIndex++; + } + + function root() external view override(IFrontier) returns (bytes32) { + uint256 next = nextIndex; + if (next == 0) { + return zeros[DEPTH]; + } + if (next == SIZE) { + return frontier[DEPTH]; + } + + uint256 index = next - 1; + uint256 level = _computeLevel(index); + + // We should start at the highest frontier level with a left leaf + bytes32 temp = frontier[level]; + + uint256 bits = index >> level; + for (uint256 i = level; i < DEPTH; i++) { + bool isRight = bits & 1 == 1; + if (isRight) { + if (frontier[i] == temp) { + // We will never hit the case that frontier[i] == temp + // because this require that frontier[i] is the right child + // and in that case we started higher up the tree + revert("Mistakes were made"); + } + temp = sha256(bytes.concat(frontier[i], temp)); + } else { + temp = sha256(bytes.concat(temp, zeros[i])); + } + bits >>= 1; + } + + return temp; + } + + function _computeLevel(uint256 _leafIndex) internal pure returns (uint256) { + // The number of trailing ones is how many times in a row we are the right child. + // e.g., each time this happens we go another layer up to update the parent. + uint256 count = 0; + uint256 index = _leafIndex; + while (index & 1 == 1) { + count++; + index >>= 1; + } + return count; + } +} diff --git a/l1-contracts/test/decoders/Base.sol b/l1-contracts/test/decoders/Base.sol index c891194014d..0ce56d424e9 100644 --- a/l1-contracts/test/decoders/Base.sol +++ b/l1-contracts/test/decoders/Base.sol @@ -49,6 +49,8 @@ contract DecoderBase is Test { struct GlobalVariables { uint256 blockNumber; uint256 chainId; + address coinbase; + bytes32 feeRecipient; uint256 timestamp; uint256 version; } diff --git a/l1-contracts/test/decoders/Decoder.t.sol b/l1-contracts/test/decoders/Decoder.t.sol index cde3eee14b3..58ab1a0f7d7 100644 --- a/l1-contracts/test/decoders/Decoder.t.sol +++ b/l1-contracts/test/decoders/Decoder.t.sol @@ -71,6 +71,10 @@ contract DecoderTest is DecoderBase { assertEq(header.globalVariables.chainId, globalVariables.chainId, "Invalid chain Id"); assertEq(header.globalVariables.timestamp, globalVariables.timestamp, "Invalid timestamp"); assertEq(header.globalVariables.version, globalVariables.version, "Invalid version"); + assertEq(header.globalVariables.coinbase, globalVariables.coinbase, "Invalid coinbase"); + assertEq( + header.globalVariables.feeRecipient, globalVariables.feeRecipient, "Invalid feeRecipient" + ); } // StateReference diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index bed87d58ed3..3cbf3656ac5 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -35,7 +35,7 @@ ] }, "block": { - "archive": "0x1a11e8b1d440a44deef8aa8e4eec8f476e780ee6eac2d7d64b09c66b8063ee11", + "archive": "0x14a951a26d6098de2390ac479cb28db93d0482161477de772c2fd031c79c9f59", "body": "0x000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000", "calldataHash": "0x5b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a7", "decodedHeader": { @@ -44,11 +44,13 @@ "blockNumber": 1, "chainId": 31337, "timestamp": 0, - "version": 1 + "version": 1, + "coinbase": "0xc4359d907ae6de5e4b9d07d925b457ce3305d626", + "feeRecipient": "0x10d7010b30b1064969934e8350d3c076417497edb99dea7e8d20ae05b54fae51" }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02" + "root": "0x1213a7f84b7be98d122a1b7e15013610eacb74b328c20f369588569b1f6272c4" }, "stateReference": { "l1ToL2MessageTree": { @@ -75,8 +77,8 @@ } } }, - "header": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02000000015b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000041ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + "header": "0x1213a7f84b7be98d122a1b7e15013610eacb74b328c20f369588569b1f6272c4000000015b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000041ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000c4359d907ae6de5e4b9d07d925b457ce3305d62610d7010b30b1064969934e8350d3c076417497edb99dea7e8d20ae05b54fae51", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x1476d6b0483d0d5fc4c9d3b04f50105d97a06bb01054ec7acccac3ff6c85f960" + "publicInputsHash": "0x2b47f887f6364fbfa291b88a26a6daba24095ce7f5b65e03a50b014b05bba4fb" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/empty_block_1.json b/l1-contracts/test/fixtures/empty_block_1.json index 2d4639fc25f..981f2b53a7a 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -35,7 +35,7 @@ ] }, "block": { - "archive": "0x2068f1adad2617364389ebe8a1eb54b969af5f5145be43080dce735a0edb0e3e", + "archive": "0x26e8b2fd7165996139b4741d25ad12bfce06a00fa62979ef4d147268d3a9c1e5", "body": "0x000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000", "calldataHash": "0x5b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a7", "decodedHeader": { @@ -43,12 +43,14 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1706272901, - "version": 1 + "timestamp": 1707224997, + "version": 1, + "coinbase": "0xc4359d907ae6de5e4b9d07d925b457ce3305d626", + "feeRecipient": "0x10d7010b30b1064969934e8350d3c076417497edb99dea7e8d20ae05b54fae51" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1a11e8b1d440a44deef8aa8e4eec8f476e780ee6eac2d7d64b09c66b8063ee11" + "root": "0x14a951a26d6098de2390ac479cb28db93d0482161477de772c2fd031c79c9f59" }, "stateReference": { "l1ToL2MessageTree": { @@ -75,8 +77,8 @@ } } }, - "header": "0x1a11e8b1d440a44deef8aa8e4eec8f476e780ee6eac2d7d64b09c66b8063ee11000000025b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000081ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065b3a885", + "header": "0x14a951a26d6098de2390ac479cb28db93d0482161477de772c2fd031c79c9f59000000025b89af3c0d0bf66ac691697d317108e8f51bb8e3217d56f152b80867ad25d4a71864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000081ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065c22fa5c4359d907ae6de5e4b9d07d925b457ce3305d62610d7010b30b1064969934e8350d3c076417497edb99dea7e8d20ae05b54fae51", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x2c3372274a0c11108d634c3f133ae26232b662ca28c127f1710d92645d206b72" + "publicInputsHash": "0x14313fd49d05dcd2782452aed9a79bfcacaf4230df39100c9b1ff85417249e83" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_0.json b/l1-contracts/test/fixtures/mixed_block_0.json index 11e14b9d7a4..c08897ddadf 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -52,20 +52,22 @@ ] }, "block": { - "archive": "0x1f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c41810907", - "body": "0x000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000061900000008000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003410000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401000000041c72e330b60e0052863df88b19ebb482d412b0a7bbb2fabb9347be5e59453d10078d263242fac5a2ad544b5005bcea367ebc04e01ff7ca279650bc63d9488ac304ad4d395e21ea570da47bf574569c6526312c5c7ad63a6d248f694e5c81c2b60e12693b411d9eb8f564aa43f4aa14e3e30f8574425a6d6491416332b77d2709000000000000000000000000000000000000000000000000000000000000104041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000010c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c10000000000000000000000000000000000000000000000000000000000001100010101010101010101010101010101010101010100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc00000090ba31e106be659f28af9e2af50d26e9d288793bd2916d001e72b890141088e28edab510df4a749b7353013aea3159668294ffb417f35ce95cb6fce2f0221d812cc4857d625e1a6de8ef2b35b36213ab4616286de404f3fc6463e0e8b3c8f6f8251f122191b6e9fbb1c2cf167dabda8f39040a8bac6c883f89b0ab3b0c1e42bfe51bc975cc64a95028e12e3973e801f67b00000090cf1a7b1afc016e43b921a58db2db12a3e5898a193f7d50907562b5b85e41cadeecb846519ea542dd1629c46544286079c71deb32cccedd1f1174973b6a67aa3aaf1d2383f3220c9364db3bab5e636a6d08c44b3ed62aff9c6317097a655ca306b03eeeb7a30bc8d67d1fca62afb7519e13d782777f78caaf2a8d5bb2ca25f1bb30c4507bb38b914e1cb6de394c47eaff00000090972270ea28acbcd6a954b5e146cee856dd3ef968cbffea1b2e26fe8aa06971f0e8ed6e16de6c6d16da52a856d163d5d489885cbcc8e5389d1fc374fa7fa2722146b3e3ed216d5458023f295c4760c2ea1ad29613ffd7a06c1c8e789be58df9bffcbc51b33964b639a56bc5dd1a51387812f2a6d70cef7584e1fd429ffeea5282e9e526246a41da20e503971e2aab4ec5000001bc00000090eb7ade43f1e76dbee20da4688d5b051f943bae0e4aa13d6c3df97fc368f76d43550019246b1190e00cb20ad8eed3290d9589d0887c900f7dd563e46a8d1cd032130f47fed6c734a21da566075c469ca9006b482df4c9cc45c3666f721cd8f70701754b25a3f1fb4e350ee5fe39bc3ffa18c8563a2f6f82742f48612ba792506205880c01d57a739598bf190feb8596240000009056db89a8f50db43b830026ae48dd55257eca77acda80258fed70ab6544a1da8dc8a5cbf5cd2a6ce9ca2983cd08679b8acf024ec18107b7bae3477de8aaace0d672c802658736d0654a7fe35b810ed34809f0190f92b4a8a070679832bd2f978d06839aa3c12f7263facc03ded7b515d606ec5141d8fdecb686790d39f0f7f380b056b8d8eec3e12522d779459764092100000090255a139bd500720e3731bb9a6c79d111a39618b2e5f7c530ac9847bf2945c5fd11726efd1664ebd7c5ca43a9f001e6e9048151ec3ae655178efecb510735cda8838001ca728b89c9cff98831485a0ad51b5a9d5ad1566b6ce5872da25282fba1e8fb1ab733ceaa1e4cdd5714b5e0d1ba1a34e60123ff9adef7a9aafa7a70afad2b0150256f6bcb582edcdd802322f455000001bc00000090ad3145489922aa1ce466b9c6c7d72ab3806cbfe1142b29704248fb092ffcae20ce010695fada64864571f02888d1a20a5aa6c85bd719753e5a24b112be2165771eeb9f9734c57044eb2be7e8824c630d14af1b5a23cafb9ffb3449c13ad139c1625cce3cf18a30dba95f89318bc26dca1a788d92b8c8cdba555a3b56f61c2702834346ea4b9c995f2a62832453c95ba200000090efb7e3ad6436cf40a50d456603b484b0790c484345d91ef82df22727bf83359189f64f7647567c4a62d967b7c08d97834b0acbcc233dab3cfd4001f19cc05e406707a1752e03e79919a4a5d58e71b29720aafbc5877bc7c2132627780a3c8028b8e670168e23175d776a0791e9dd0ed1005288a9a0ce98fa9918d9e40308c5022e264ba1f04a36c3e747fa8e039698020000009003294bc41bb24fe5cc42ec61e2c7fe1bd0d0a90a37f04a9860159e21cd2ada613cdb72c0a60eadd711d0a14c1fbb8f60840c4ec94c91a74f2f65e989785b3a28abe0876640a898cfd1cd4cf1702ba78d2e9cff04a1744646744b510798e0c4c1d2a1273fb63a9a8fcdfcfc6511b2e3170d66e31114b708a4c85eec819ce2a81d8b3fb0e14b886cf418f5f904818a9513000001bc00000090fc0e40cf1531f14a598f44838136445b088a2a2f45cbbab5da3cc3dcd3a50d9501b376680602ef03fde8f0efbf5e64bdfcd04d2be10467899db77b87f7082e6bb9606f2b3f6578958f7738aeccc2f998135d91d51804d9bd5af9f9bf0cc082cfb4d914ec78b3717588a607d28866895a26d3dbf67613eb7b88507e96c36f8eb3f6d2f035ff29601a7070db25482ca6480000009097af660dc945d784adf1e74f09c76c0d8070aba3c837dd839e01e1fe905a526b297da15eb220ead6988026a4ccd36544d2a2cde5d68b63179505ac1cf61556c5fcb06155a299e98b76d478dfee7254b10474f23c1f1d780f3525ffcaab169a947e8b42a2b384b2a5733a408d8713510a246fbbedfa20466f9551191746bc8bbc612e2d8605f9d70a1ab9ab78393658ed0000009099c961b18e91d5f06f29cabf320bccb0050d377bdacc0b811a1a5401d046ef2d6fd59c1434c6c7f7f658467a1c5df79c6bae907a28dae0ccd73ca52e7148d36d960bf13af6a158381b2b1d3e3d32085c2953c851420fcfd51c7da4402646bdf8b70fce51677ea205131cc5985b6c36661e93db19cb61526afd04356dbd7ae0b742b27c4dfb3866949e5958ca3e842ba9000001bc0000009002c28f7f35048d85da57163a88bae6c1ce86084bcb10f1f2473b9fcfe3c4d31e696db7c1f176d59a8662fd98179eb6bba3d3fdbd9380987823949f7f6670862992d060df1bb03fc7be8e56ea31d1049e25eab063ba144bd855dafe6615b7e3394519bb08fdbd277645f235e627d8f5c922f064f572ff7e9e5d3793d8f17f7be2eb642ef66ab2c937f234ab302db9c01600000090ced262f3fc9841eacecf4ac79ece1a6f329883551b495dc904f1da4fc7149c19b0af3b589f525b192585ad7cf11d37296750f89b42c2f74c78a4cb7b301b08f4995e5ac277c65466654192ed8b7fad9f02e2c8c9b67aec2e4fe51fd582b065a0b1295023088671f1656ef0c899cfd14e24d3823a3b5bf33025daffbe6667c86a071ab485bdcfe78fd70f4ca591a7744800000090bcc6b58413d5bd230d8ecb4e92873d5d59f603c97f90dc0f13a47cedb485246cef9bb7fb9eeb97588ef15e6a560e7807a3bf30c19222223c73d5495e514f9d94ab925eb2efc5cc009abd85306a1891fc06e743b5b79bf848dcadfede5215546b2475e9ba3c3bd3c90a59b06b298c33b30bd6ca5d1de7b231868378fbe77a66d4d7bd8acdee3b91552036f1786a899f8e000001bc000000907d8152fafb9430eb4212fd07e22ef189b74e1a61840e63bac60ae533b51a4ac663cf6f1eea1b7b005de75030992f3df13520fee65eafcbf284055d95061770dd76993321a449b17b3ba8765d4eb25a5e13f3ccc51ccddee670bf64573ede4d604f38baad0e7b745eaeacd14706d15dfc23e21b0eb00589c0b08468185419290deb27e4dbe077c3348d9ab03babad010d00000090ae769576c6e1adaac865282f54be54d7a32f397c72f6b7cac17b3632dc2b7ea2a991549df2d8cc79a8619bf84dffaf8ba5b8032566047508ff713890d1502f9b6c223c2f417db257ac5cd0eb24770faa230c8a792a315873eb4dd5c089ac5ddb21e7f1be282d2a7474d25b7a76a5eb49094555d3778101e0d87b2fc3634faa9e870274db85687e1fb9985a3bccdec32700000090d6419ea66762388b744d8554f1d12fa61e186e87ef656d9fd43afe120faaf85ca3b919bb9e1159b26c6f9373ed8900ec9b07958a7fa94122767e8fbe83fe25bd25ee9b7bbc215169cd5fcd472d29631a2c85122496dc2a16064f0a4d971d00213573c1be7ab46d9cb1688b7a6b8ad6c715cad16545eccd57cfe4e009769a42f43d35f94afb0ed37f56497a4083b4c1c9000001bc00000090578657302fbb2f8cd1f948c6f7ec702485bbb02d000e49b0bb270e4ba42aaed079b180b57324b619358a65bb30e1e99e005eff7cab46e6ebad6a24bc271dc6bf596cfef2bed50660ee5912c7261f602018fe7c0a8aa0039f79e2d7ae32bb2b3e50a55aaf88f6facebeb285461edd481d0853f2e92bc2962d3abd76ee05c051fd4c616902b3da929fbe7147c9be20b33900000090ff20a189a61ff5160a797d3bbf9fa8fe42a4a718dff147034496e00803e918b5010db5c160bdcc2cd20b453f80f52d555e28addc5b3eb493a14a5eb24bb7d6749e725eddb2d15b7abba4ff1d6f51058b064750b8541970f26baee4f5daa75badc7d27cc7de416972251b974fc47fdd2617e2548554329d272dca1848dd9ca17a8655e9c79ed8d65b9e626bb5f4c195cb00000090da7b1475f1369e5dd95e3974f0a61d381e717cd227a6c907b6f79e25348e2de665ce82a5ef35bc7bc8b7186cf954ec7975e763a76e2b4455c0e8f9f6c95044018b6a6612a3ed58f397c92b4f4a94bcc222ffc4c50503009eaf6898361f5cee52f86d18168916c6d828f762c4e9f1e43201d54a8d7d9e228d202cf6e2d7b7732031cf021496f45cc607e5c772ab64c1ce000001bc0000009082828bd7ea8bd0238eb233d84a6d8eb81473be3048e55f7eaebaad27bef571d806ca99b1583a0ff91d2c2dc5c7165b0f8b5291d069f9041f8c134e58abf0b8a7ed410584e83b3570d224a946973edb9304615a0e468b252dfba310ee65f9daa91e885c7d6f41400876430e7e4283cce8164343d81d0d48a970c57c9b641904f1f43584464f43e42fc3e504dc1aa5b0ac00000090b29129ac91e149c208ee449e9369c39ddea7549359465c1dd7b537c1b768e9afc8ce9aadc7064f10f070eff11d526bc86e5c59efc0b1963dd088c344a0d961214951ba851afc71961109521ed643fabd1bc4146b11f60f52a707ded2c1437eed6621c9298cc689d29573092bd5a5d1ec051ac56823011cb0aca04c910b86eb432ccac18e0713ad65ac0e80fd6461220d00000090f264701ba46324c881a50c29a2cbe56d8ce1d52cb12279b9e666d2c821c641e95e79769ea31329b8d108b5889d12aba3fd22803ced02ea159e5ddd413a810e0147497bfe0595045f5afb828074f87841059e29b9947ee7e131674f694e159fd6fa48816b194a40672220689a3ea39ba51a499df559f617205c47ea0b29ccbe38e77afa2f22901a6ac19ecc44b25e024900000e00000001bc0000009044de4596fcd2174f04e08f5878714d65f924bc121137aca1179967c71b97c9f9880aa849d962e6c2194daa6d78a35dd8d7a0d6267bd4014fbf4618b0f7f3b35a8bce6488b5fd9f771288400410d81946029daab01041cabdff51997bda933b63431573fe8ce751f87b9b6640a6ac76e62b89ff965f5678521288c80e7d924586991cc8bd828803774af1110ad6af2d1400000090955411b3931838621ad246ecad090ea826dd4ddb7bba4f2d692e73d6fbe197f0754db7d8cc340a993078595b2e56c9727cbee8412af57451e251a28716a32c0aab99361800b9c9eedbe58a70207b8dc50cfb4c5670dcf4e3dea0b0d90611be362f0811e4738223810dda308e068502b1275033156d228b2ac72d5c13783764ecaf93fdabb89c3a60dd2511eef546ed47000000901a490364cabc8dcd69b5311f1a3146fd1ce7b2ed487e7770cf9edb318ada757cc7d5a5ab38ff4af623532d17a94d6a0ce99967aae09a722e634691ef15ce8f241bf3b34849564ced406f04e40248751819b7222d607629479e4e0bb7d076d7639c8f6ebb93530fb24bbc03e884507e002530933112acb5c27690c1babfe86191035189c8c17c66fdfcbbdbacd583934f000001bc0000009054be3def72a403f5c2c9e65dfddf409582d462514312202f646d792003166b0f85955514e5e307e9935bbcc9995404afe1eb12bf2ec671eadaf9a846782a983585347a2cf8d5682e9fec25a588fe81eb13ba9a153f0210840b5a343c1223e88a80c467332cb74375602f02a409346000107e5340ac4ccaad5b3281cfdbe0212f640df8b676de03b5f8540623253c6b7700000090a0a2767711576ce8e6cd6b6b1ae5cd8686785990afde849f7029ace4c60f67f07b05231f390f23d2baadd5f0e76b9a5ebde244872dd5757180456cec054c62641187283fe89adb7657866faf7c6141320ab18c2342b86331365ea3f744baeec431a00e8c111f1f8503a7362f60f6eaac268c0ff4448be08b68f919909b6846c9b64e18a4ae9d7e6a640d2d3b45ad9a5c00000090174b52e1c4cc5baa99d81bd062bcedcc8055fdef765174be6dd9306fa931d88888d8d069757b1c6901c95158e8536627f997f10126249fb4bfa15f1a252ebc4a8f75bf5ab07db6c530c9f4887381c5f30cd5ada4fa5f13eac5014e84e16fe8be85fcee722e18675ec59856d364338a150167f37baa8120dff1c3a2422373f34b36cc620d32458375f28073ecd0e89875000001bc000000902a4d89127259186300e7dcefe2b9a3c51c3ce7262745575c1893cb6ec67db59cfd6d97faf4d955b98d3a736ef3c2762b096627ff8d84c7b9a766e5b910377ace261a27c57f67e454fc74b3b65be2310d00d4833db1c3ab4bcb66cc02e8e389148c4c24cf6fd4759afc32e54948a302a5239b055f5e3b16ad3dde597a249742ca3151434363779a42e0900689025ab25000000090a47255e90a224451cddb8819b9c15284c0ab2c79cb98278b3c175dff2e628552793b1e850680507fb33a41f13167445f80dafd01f76d5eed4217c123f7414f2475eff882cd5e6c46216537ceb57a40482e307213037d9a9a09dc1446d1a477b95055de78be0a8b6f39aee6e84b9fb5a8022146920ba50aa9621192b700a6068dfb8e2174d2ac773989feecc6d28261b30000009031dac21a1433f531dd18b1632847fc0dde1c17bb02d5ab354c02f4acc795c5a8cff0b773a547814cd9831bcb9abe8e5acd292deb1df4d6e6dcd1a820e3c17a175c89b40c49f67a7eea27e549af42b416198cc216321d12a56329fc95f648f02fa3224088cb61154ecfe1b9628a5747ef26479590b8bdb8b68b2688ec9b7436a3e0602787ee7c1dc53d6cc2e141c9e27a000001bc0000009042036b440f7bbaa76f6cfdc9b78b13c6ed8954565059bbe1b6f3dfb5bd88c2f28a2f29e0e5c261c25a2e9d7e511d072bde43fd9809796effe69e8aea3be54508d8a9fb29bb6a2a2a9a4851820c90b2611fa5229daf2fda66f0832ba0b177916de6245b6144a4d9fd5a6d84d0b3d09b5f138a8fd41f0245790f51d769418351eba188c24422e29d28b6dcfa5e108a5ab50000009029627be6070f320d9c0094d3745572911c217ee1889a111119f5bfea6769c574a55a30db964362ea4f37cc38d99b125bd96910ad35931dfcc5e1d60460cbcdbcfcadc88b1c3c31541b7bb37f546b4dc91eb9f46857491b80dc5b1a6f3b7d335c2c5eff3fea40db67a556f82ad31b54452f733fcefdc204055851f24bfe942753d120dacedbb004351ae40fbcbc40e44700000090e77c6e4d7f802613a018998785edcbd7f2d0fe43fc87b5297c90f040a86854ddac359d6ae8bea1151e3625d27b5d726a6973ac1a715016b94f596652f1b5c34335c29db6a74dc5f870523c9da04268891c8fb300114e4a14bc53480655c4b2b0ae1b32d51db9e05ab97eb74447c662aa26552991acc5c288822e24649477c17ba04d8173c6a271005b74ba702f19f6e9000001bc0000009033b75699124df3a003208e2f077775a0c0cf6b5f43b10d007ac669f67830f4186c27e63d53e8d10ec7e04a587d330a93303ccdce48e4d883814687d33c3c6863376ed002b2a9a3bb715c93b9a7077575186f9f30356dc5e9bbfbc7448ac599026c258f7cfcecf3b1386812f03e6760b129f10aab131e1fd053fffa9e69f0affaa6005b7788f7176ff1add5b4eb021ba8000000900d5f42e0a54bb5cd368f9c464ec55077b38560a2dd87b7fcc8592304c63f8b713bae6a5f6af20ab8ed03a6b800a12059677496aba92268e1d36f3630ce184a2547b161ba35ad3ec88535cdba733d0ad306a7f349d6ea6ba73641ffe063da5e81170232c57e6814e422518f2ed1d5b40724deff7d2e8c352ee005a3bbc20bee5b8a835ffd076356fcd10cc7ca052fb72600000090485c8561600c40dff828e00dc64d85de0386db3cd95adf13dc343e26c62cbcbd50e4f230a7262fe5faca058dcf76603cd258d997d93d2804bdeca854114dee374b14a94cba4bcf81454a0e5cfdcf7e071b8700e9a230d063828289d9db02e2f79f84dbd59221b39851b0f9c14a326a9509a44efa10eaf2de68501bc0d20799417ae2b08b140581df7fd7809666f48878000001bc00000090793c45f5f8ce488890d12547e0be78376fcffb61c9ba15909bd0d32c4863702f7a4308e7be8214eda46614b17ec59046177137f2fd4191f5214e9035bb1307efa167cb0f9dfcde8ad8add21435e6dd4f23fca789a52337d770bb3239c51752950f463602450dd61e38a292f7467c9bbb0236993135d3c1d9fb5c7210bd33fc7f5068db47cd18a9cc57e585c5e05f526e00000090f849a580d2493d30febe102d84a596007bb41749bcd698232336b52a1e0909ad1ce9c8ba3aad02134ae5b160ebcbabe506d9b7db0a935349e979b8873be837775b6e688777cae831c426aa99a5b95fd42c5a899c819de878d741f833adce678a55148c00e3e9ad526fd8e8824367e48113412b6ebd36bfd1eda1129277085d388afc79c6e0c9c5130d377378ffc8c2b3000000901a77e1fdf2943eb04ad871b97872d58513b87084509e93626d91fb435e5cfa0bb54ff8bc4db8d12df9a027c4f5cd281b5ef6ca8e187d878eb2c3dc3f69df34b7a45828827534373c7857f949f23ab28726f8338613dabee6775bce5af93968516d4b88cde4e1e835f389af54a07f98bb2f583429751b5c5743de521b13e42b23dd3ca73823a09df3cbf95161056e8727000001bc00000090a526b2ab5d1424ace96e20ea34dbf9260b792747a1650ec62bfdc8c733c005d018f5143a029a821c22cb72a30c3d32a9a9293e905463204cec2133071ef13a270a49f163a01a7788a27b017c8d80f84003705bcf1f46491f774b4b66a93884c7e204d37b90712af352cc5369cc5bd64716bb58ad99f05542c64b16267213a12549a9f3dc14a7d0b2c9ed43f170293c31000000904d582dd6d58282e96ed78e85573a6bbee047a622bc85480221f99451687ac7e2bfb2bc7e7d6c1186fd0dd8db4f13021a6163e3300104f0594771afe76561fbccd40cd7ea868e4b3788bd8534c4f301b2006810388a2e469d05393d0c3f308af465af0511a02e0875951b1f90ee40338d1080f959493b6d44e1a4cf65a157e779f21c53efe38c7ef3d907887e354ab90b0000009053547b42020ac7e26e414c1b59a37ae16b2e7fee712797526049fecca537a0ec3e3682a0c6bf499dc5bd1ebd7f002a340e9e1788430993454d5e1d63e8f814e0dc25967f318695e3058c6b31322348ec3041f03ed390bd0f98c27f9515aad0d8ca13ef9b231be19633d8897002c590ae1770f43809e212761fb5b381ac99adb7f0f77b1f8f1cea86b4580e6e7fec82a9000001bc00000090ed283635593ca3f7d15a67e70784417958b09467d558ab99746adb7fb73519adcbb7e3a07bedf202a71f9ea17787b40bcd9e2b3d8c543ca2c5c21841412a0e371b735971eedf6b99bd29037e3fb9fb69132446fcc638762adb7d51818d49bffe2e53baff09e8544b330a1b5303b623fa1735d51c1ac2b6c492c9c84d1a6a55026ad443d5e385d0565e9ab987e8ee4142000000907a3aa2434f8a0cce281947d36d27b0e4e74fcd817192a81b6afd27de57f6e573b0ac854034d4a98443f2f11bdba4657ed7807ad8844c1273300e69b8c97dd2f6357a79cb090a0d3f8a1ea3aaf2eb2fba2feea06a3e822e5467185d783c488c59b7bbc3f2b61b9789e490a4e9f3d07e091ffdd6584cdc4af094e14d135133008ed82f86785bd7e8038889155ae9d98620000000901e128afb71d9690e6a4489d62164e5fcc2ef689bf0d6fc7990b7ea5c9cf012387c6c2c5591f66ef06662b282e37ae620e43eb43cf5827314f05aa8707fd593282b096bd0244d3e6714a396396aa23dd90ea70748e823e25d9abe06b2e098a39ffc83c00ae2facf8007ff3c87b0bd02721655b67ba635dbd904c6a289abb1a67e40e8070e89e550d233f908c47e06c3c100000e00000001bc00000090093f193e90ad5fcc72e550a3f0a76dc9ee968de5270bd8ce9c08172fb4c2f3b5a26da0fef66c84858b74f49798dd226b31c81c4312da9d68caad1b3c8b96dbd259eace348007a70e934974220895d3680522475c527adb8f5a4204e4587d46425b8b51451a66c41718931d544c99763b0ac2a4642ee3bdbd4581c9321d21412810cc7418e358adf228510ede35175ba8000000909f933c55a67a8891db1b2d254dbfdc0c1d9b7728a5cb7a0d9d2332c8f231821c5e89e29bf226603d34b2e080b52f4691c0ef7542efe42a4ccb99d41b69c1dcde57fc713ead365379c54479678690b5b30bc2370bc15d494b92f87312d7e9f490d19473a552601a755dc3ae5c081f0a672616a830f55ccd94db52d6b2d47ddf4aacde4e8d578bc7a6d4b4aa7c8aa37118000000906a096f39f3c3ffe3cb67047edcf09f5b852743fce0f1a5e86fab0d998254a71d45b29ad3cd74ec13b9eb9c9834eda1357737ba05e4910a1972f70155999e0df4dd8e990d05989768e4222e17f1e6ee1c218c9f0b2b93ca885905f55be91c92316bef67aee818862317377a4c834f01e52bd04ccdd32305997766884206a1e66aafe4ce850160c6bf1409e4d7cc2862f2000001bc00000090fb0977cc718446ec0e65edaab214165c8ab241eb044ed8e8e90655276091b2caa5b86cd7a216faf034ae4e3dd1e16bb749da5771dd976d8fef43d9fe00f213731dad21fe720481b4202ee296c80be87f0d451f969f70c2ab0745157ff132bcb72f557f429a71d99f757c33c1a807f39e200398cee44bb61e4bbe4ad8cf534f21d221eda0163937272c18a849011b2bdd000000906ad3b55017ea4cf98784aebdbdbba67c19b26a55d9f145b07b7a2264dd5bcce3fdf59ccd88144076fb3015b8928ad38df1f939577eb411f8e1ad8959b5cb1dfa102b127c75a185c8a7911a39a4950770167f7d4a5c0c4a3e154c7ab738608e8135426db350320a6651f9187e242031d928de5e898cc59d1d9e627ae27276bb6e488dcacc1eef5d3e2068fad43df6f9fd000000905088875ac73652da0184f89480a4e6353e891980f990cdbb3cbc00629baeeee6283b7334870127cb2a1e888816e32f44fc89b53cbeddf76eac4ba0c80080e33cd101ca1a16699149271629b994da0c741d6fb377af7f696feda2d648b7fb702462ed652b61895962fc725591d61aa4d918ee63a514436b5b7ae16ccbc59ceccb19fa98ff49d4dbb3645370682986d774000001bc00000090ddf0918144b46250424d393f02144553c7de44279ca2293101e336963aedf73ea2f3bb7ce6cb414a71f93698d6ff4644767674b827463cff11decac38484077c251d1ec137b40ae382b576c7ee06c2a727cc97d0bab880a919ec3a647ee4f573eefe111af28c4c61f660eb20afd7a92d03ef2108d1a0b8002013c9c85e4bafc39100fbeb3269cd2057e54372c4ea0c0400000090aa319ccef974a6bbb46abdff5121f590f0b037081ab8b5da9e648292d4915fecc40bc691abd959b2e690c40f5484a1079fe2daf181106622a366869bf5d91dd8df73a59ee059f52e6447d7e831c1c31720a425a18c509875a514216d3b85797c8eb73e451153fbfb3dd21b8865989f9e1265c57271318d4d43d0f1b4faf7c32e52f82fb8eeed4b57d7e1194449734c2300000090ac0b574712612f176bef83fd0f812b1a100ab33f0c4ac5b9f509eba019429cc2312468493bb0e8d10603f8a21ef4ce9fba8102dd23dcc4c05cda8435bbe30b2ec877acb49ed250daf1c502572f2faafa032b4de8ab4eec8ea3d4d5f4fc039094331c3406fe8ce09f2d8697134c44581c1963f64648ee9a3b5ce0bb52b9c9983179f18fab2ef9f7e4368e16d72a8ae399000001bc00000090d5cda54efbbeb6d54ed2496af376a262cb98bf36031064f72399c7ac2be9864ee33988b56d96393fb7d2eed6d9691d9d8b52ab6dc8bf1a78d521103869c50434aee072583799f9c483b9dd669092e08e0e0609065426a6af1eccf3c216d575aa8bc1a893ec1600392b4786f9286ba5b31ca5f04127a582cb84ba9e3b70e5e97226a411c4d3eb275bccc5e25b483dff91000000905c9e9fd56e8d560e67b778b23277cfea9bd231347a999326e3a264ccc419577b44ad76169a1c2869e665b340ddcbc7a9487ce6b0495d70da9d771c9fa10b28f24ad3f16dbcac3cb1d014f0180d8cc56e083ea65e5c4580b6fcce0ed318bccceca8ed4138f01a695d6ca8e422199c601c218a1037d1d3ad0ad0571f65a3eb5172fae3e14b9762a594df1e52a041e565ec00000090ee81921fadc592d08ec6dacb28d75464ff4871184e26753752afcd70424a7dcce16bfe5880f59d9c5c627b0c340ed6de8243d196fdd6c175a6b1f574c33facd590e5214f04db6b403026e6c8f5e459d92af77b3d45409a6ce29c570b5e0e255857bcf620ce7bd8fbaffbcefbd2f7cd8e10c45b15a6ecb3ae017bd588f5f0b2077136572a8d1b97acf8368e4d9ef3c4b6000001bc0000009094cea4a845852d5205a71eab1377a763da5fbe70ea95e68602ed9530d706e9734fff6f0f63d1c1badfc518e6c71eeff7341d3839d377e6f2565a28ea7d8a9dc778e96eaf95ea3df8174f47ca08d6d8711dca8e742fafed2e609e73f17f2c1c9ab3cdfbaeecc4051c2e8ee2fc80bcdc622297c7914d843c2111c3a2f36286aa1e92b62b22c98b1702732b18461fcd897b000000902564f7b6e01aeb829a03c67cfe9b90d02bf5d0a3490c841cca0eb13d43385c4c9a6c44e43b6a97d7a6cf823aa6212481eea0d50cdb78394e37ad9c208b6319a06c29ac7a4fb39f6512d2c7aa585d4e112a2fab41500e645f0e48daefea78b5250f0af39036eadd04ac3f8d1ea70d55552071d72c960f1ccab956353278ea0b73197f90fe7991a91617f047f265b6dd7b00000090ffe5b429f4cecba7f308784f79f9171cb8cbf0cf688af5f6f345d43f45f9bdd209f58424886104c6d8ef1c599135d142ef79c26de39088f5a6da5fc21ac20253dfd7f02c28a90b6f4f568f6fbacdcd360248c6500072be21b1a8a952e3f9f6429fb8a509ea76054cadede9d738cc880f037cc0726440fbec580757be0ef5f00860cb5aded77968531e3effe172d52a7e000001bc00000090225391f1f07678b6218786b0fb16dcd6f703fdae693fc8947f64f59f9ecbf8608f2b2fe7673bf7212adc28f930c6c679241913e05e918c1021d1baab8165c492c234d874565789f555f35bd44c057e021345c0508967c6eec0503c73cdf25e17c20d22407bb65dbdb2438c991aadade9034e536ce6c41c310897c7aa76570d36fe4580bc72140a977cc031903282426d000000905a5b8d400eba99dc5f3f2003a81b5c476ff36e092e77f4814fc902c561feec7a616ee7aa66bf9e1e9d63427a0b17654bd61d0515aab1329ab28bd5e1d778ed0cf4b8fb27a666fffb37bffa867c7220ea03da67528e3c0d1591ca330b61894ee9e794c8e5f50b8d6ed366b0ac5d78e7142d0293960d9741725c51cfb2ec7edeebefedb9a769256f0c9154725d3854d57a0000009059afadfe209eba3c172cebb6ca552534b448a6471b27582119547321032be5d3188fea33c8ed8c3d60cb4ed488d572515d463a2d0ddd3ef6d237a7658585408860f2d2390cd44c6e5c27fbd7c3a6c9e6238d70cd02964baef06b1907ec9effe1d7c3be3f6c44b725607e57d503298ba119ca39e81a27a701bcc23319aa7a31b583b2aa5c5fa946f762d40389029d0a8a000001bc0000009019f18b0993ea58cc0e60a6ab12d890658ffbc10abba2deb8ae8da0e5ed86deb44c46257de38fcd3a801f11f69bb609d282b440cc5177f384f131cb5b400e4058f53fbecdafc5235360c2b0a04bf1dfd2186e31047ff1c0dc33298124a02b36528ff0012e161cf63bbfe5e133c713dcdd182181450fdb65bf770a28575b54a147555d352eb9793a2f380441fcaf35cd4600000090eef87e9ca7fc37aa991f73e09b86f3fe5253bcfbbc30b979a631b36bbff441f90f292ad60eb2769cb54e467f63b16db29c06550f96c1430c720f9c2071ee2ac78e48b81ae4cf2afda75505db1ba072b00d7de00e7e8f19f99380e6c3042828a8f7befe8f557fec8deee36203a6cb78372ea43ef82b92e4ca5f36bb118ef05c6f107358a4c9d0bedc1e42b032b7c30f4f00000090a3181d013c7c27c80b6ed6302110e44c89fd98c2fb3ff2bde91a2dac237a0a8c1b9790201524d4add68c0e3fa6bc6f83be980bafca18563addfabc32f4e868736eb61d3ba99b0436838a74aa0f6a27b513c6fe8080533c1c994bc365bd66127e0518029fb0d1e6357fe95e72d82579390ad10e764d612a8176912a688584f119c353e48075e7c78915c043bc6f6b9c68000001bc0000009054565047a9143d945bec3ef338e22ef38e31bcecf35d39a8ad9a53932242e8ddfbe12625d981e24ce51cba092fc1a7098017110d642316f2052b6696ef8b048764b0ec7cc884d4d38afce13c5c3b99c919448e796f40205756f1436e1e5040aa0ced2f7df5f4427286a3b50e2cc8de6609eb562e96c664a796c6e9c6ab269f8fe88b21f8f501ba5b59e56367cf0cd75c000000909410338d8a23b6f386369356c3fa8e16937394e862b9a785af0b426a1bf893341cf6b3a56f5de26e38b57943261a636b4f27f08312cbee701b210e00abd3a1cab483c190251ce200b918cece007f6f9c0f0b5b31f9005a5242a724d86e74f421c852b6672b4d346c999465a443e932190fab16bdc74f7df3b8966d6cfc74c4ae5123dd6046f525d306b76cfd90c725b9000000906ce36d5c10f1ceb7973ea03a9d07348c09843ce95e9b46b9831929db43967c60534999bab1e4d6c548d1e967bb5035eb7750c28dff8944cb6056199beb6b81f4dc42cc9721ffd2a0ae94bfa83ca753b802f53b499f999cfe44cd302b87166848eab643805261ea69b1fa606d5f94bc1f2074659ece90d207636f508a701a85a12efe6a1e9fb074885b453366792a23f200000e00000001bc0000009004d2727c81570802fd60f39187fe8139955c3293e7eb446c15f8c34b4b88800b230e7f1621f1b4105a5830a65b082f4de456ff515b9c4794f474eb33778b47e82b96bd212fe4f3d9f3b7e4dc4bfb83881ac62562528d78dfcb7e23db85f34247a5dd9af7ee24f1df1d855a488b07cd0a231dab09e0487652daafe3f5b38ba18c8b8f6c56f998699f97440ba56ac4a3ca00000090918ab44e96807c203a061120c62e8d898f5975c91cd10a40c33a7b97c57e633ab4b01c7f9e8cdb2e9b2505804360d60e07d686e68a98d59965863cb231c5864cbdeb27867dc6d3d575f6311c890d651508153bfcb90f04d88d7ae3bc27455060bbd9117c98097375f3b910fa2b1a26f51f898b19b7dee695e73f771d2a7efd51f97a1b67fb8cc6d4cc2a4fdf1315dd6400000090b6e162c9185d396449572d19f140bae3832edde96355c06f28792f352c9e0f1d16602a80a9bb4b525b0b9ef68f4eaee1f28700e97120f936f7efcfd722f383f76b22b19e022f0ca46e885d352f1990602e73ac7a250e86c2bfda2766738e5385f50188d896bbfd6d125abdebe893359101d9779b506ca9ba4be0dc69899f0d21c92aca8b85eec4ca8b6e58e8882bbeff000001bc00000090eb3d82eb845cb36112c2f181665371298b76838e12dae58ab41723d1cd3353c26c32ee720ea35760272aabd28c3fbfc75abf24faf78508bf7cf1d731074e263b286fdc2faf1c1529bf47b1184b10a62116e49384fb35a370758682bdacb2dd518fdb3a9c95b472c400be19fb9a510cf11752226b7e1ddf74eba9c1589232ee94e9bbbc4079ac97594a18ab4fa42e8b8900000090e4796a030625a284925999aca258aa4388010e731dadd1396dd25decdabaedc1658c229b604223b888e096e04b35179cc499512920ce0d63359e3b00f2b876bbc1655f4e043e3e034f0c541ca9008dc12246a72afa3aba1fbdb8c78d39bdb12ea33310ccc648575924d780396e3c5670080bffa4e9882535ae82f3ddb54962e6a4ce4bc8dc969a4ed78d286c0712d7d700000090c639050d286dc2032baf8c0feef5a51b17ae5142ad49000b4baf316ba5a6c518bcefffb78de74d207bd52b08e92fe7cc3d53852aef8d6db07b8bf8d7b2ac3efe338882570d238d89b603c10d98efac5d29e4fbe16fcad139750859f360a169cb99767b8ea4a5e4b13e1213d330dbd58d03cb09f349c8746f02da530d5ff250b6ae4dff04e844236f8b2a716e128d8bb8000001bc00000090fbae53f1c4b11b030f6572ca0fc4ecb535cd813d5136a61ab5562695386df70413d4cf697f4d63ac1a59faaeedc8dad4d41a1a457e2abe9e5bbce156c2c812bcccc0963efbdcaf5697607f383f8c778a18a241790d2081fc2ea8f42ce362704be163677c8e6377962a0a571ac8725c6e2185d8e812b2dac85eeeb0f2a2eb5f9efbb8324b504d3c00d2da408a74eac2d200000090f3d302381fc23183fcd2aa4267c5086fcac6dc506b596a91df26e2d521cec254fdfc8981e36f9c1fc4bb0df11860e7761d4e0454d061e704b3f4cefe920f09c847612885592567efa4a762887c6aad14074c4d33f30a2b2f299869ea1dd678f72db17edce419c26f167b56d396d4cc521547b04937acf726763f2ecd3c465ad8330a76a470685d1762f46235619c96f800000090efc8705e36daa95de34bf56295bde86b2ce2296fdbff32476db7e83ca1a8dd0151d7dd1bcbbcb0073d9eace69f8bbcf93df2b6dc105330ddb49f4f8d61d1a55b577b3311c325c19e380a185480d748442e6efc007caaf50c94506d1c234f71eab1c19b2a34161332e426121dcd75f9f20dd18e29f55d57daed1aff739f5ab4b44dececfec9395dc44e620020cc46cf65000001bc00000090aa9507ff4c7399f8eae915959531729413f12bec3fd965b24129b2fb0129d1fba6fe9472084590541bd879f41a404a9edf78251856f242e8a9dfc625966695b6f078127499b10dafbac54db22bf057df0146631f3ee9b6968490012cb08275b03474d5905e26705e6edc3af9ac5cab0d0fe1b514c7d92fdde0724866c047d15c07c1807e58e7484c1f82daba3c39193c0000009079d9aed959c3df77f573a4053287536874b727627dbcd5b654257498f18e325f5ce1ec47dcde04471bc1d951654b07bf09f4754a09165c2a69280622567ceee202b61407411df752ca3890373bef274c0f080bef80811bdb9c04f37947fd762c4a92d492de473bea32ec08893a50992b04eda0bf977e89cb530067ba488842ca83711d0296349d674c1ac56afcec60cf0000009090bec024b80a113256a351d1706a64766b375cfeb06cdd20d7ef75b0b3647622f1cbbfcd0a60fc16d29dda344ce39108b8a98d6a6ad2582363f622e871c611a43ae5f098122fc747e6b7627a31cb6e9d1ee2ee99aac798d2486990af2c866b6b3f8c5b3af208f72ade7b51e1cf4888c81f88e8bb1e1af435ef29b251fe6724a708dcd602b495662e2aba9df00975b1ab000001bc00000090d65e642b9d1d9a03a35426c9e93e1c9321a03b39d51954b9c72d2b6a230e8951c7aff800ad81f7bea03fdff671fd88f666cf5b0e226d8de735cba18bc07538abc29d93f42243250f1e5fe0152a83f06c0cbee8237f842b4b6ce451b40ce597bc3c4a06e3939c5a685da56af2f6a3635a0a3c1fb4ab81de5eb4b0508ecbb43df7f5050657d79092250043db9efcfa6a3500000090a0dcb21a7cd02d72b1d18d9efeb0d1da493b42304a14e012228605e5f2f2a5e044b11ad014e87e114ba74e00ba47c96ecbc5d48f7fa74868bfe0c2e00535dbecbe7e796af28dc37c4bdfb6b1ea149bf71b39f68996b10044ced1872871d90d73a35b723f46064ec7bc591d13760e5edc2786029e6c09f2dd1399697b4513db9394fef770d01cb86c21351e18fd724ced00000090dd806ae7ff708846d36f9ddbb6c8f8f8903a2f6d68a06633e707c7be0e5d584f8f51657c46f027ff5024101798a3692a554ab3b8ad185fa4a321e64de7f6fa26eda8e4768a5b8358fd6cf932a138c3ea0c03a0d6b04a12d7a0984f2ae9711483c43ae205251730357842873083c2e19c1f2d576fa667d9d5384ea6e7b2a2141d46f3770bf6eb8aa659f6d254bcb55a7e000001bc00000090892b14aba0efdd81abbd79b8791e7b14fd1b4fa765bc40491e4fddbfa21054b7ee882f95159eaa89c28821a472d33504f738edfc8c04398a16e15e8a41558349f3683a610b049e72399686c61bfd5a802460fbe9225973495867fa3c43588a6c734391f87824aef78bbf4a201e7490a32ddcca538038bd1403fa260abb9e32d21cfe381ef680f4410cca678119e1c28e000000903bf5b5f5bce33dbe74db673db3f58944f456f5276fba5a7a59e93918380b1e151c1ba18cd746607a4d0cee68e36bd17ce577cdb7d18eb7887c7698c8d9ac52af445bad20b520a4bb1733d953d00156632de35bc8ab480c2dab17a10d2d0faed1e7597a45513bad38907ab546c75ebd3a2d69ddfba64193b6633153a915dde34823f2560c0468c8822db4ec69f8b22817000000900bbab109aea3fa753bd5ffb15326043f7b3a5d20d3ac6df24379ba28804959fb4f37dcdfa8c2b17baffb16ef63b1a29229c00dc6b289ce6ce7868f656a0af73cefb428854c07972026f38e45415f40542a8d166cc63ecf982739a3b0acd7483332373e979d16a04c3eacc610fa4963e50aa445b3c940be97a6ced2b5aa8c57f29eab7e4c8548515ce6c252ed733e0e2e000001bc0000009045da1ecba3eb2713931e0edc750f695b1f1b175c6b5c52b5d3f8963446f21e117e9ecc7904ddee87ef3eaf4274dc9ef5dcb0707042a7bc2052f849af4029c5ceb3e6184066d378d21f6506cd6f44b7720cce17b80c0fb48bc6486ce98f879a87c8d65131e0caa7ceba5b9e7bea2b15a82616f160655f922b53b5f32e7d78fa77f21b6c41be2237a7d5bd5763623ed86f00000090eb156a017208ba060689d4614777b3e026b5407a0e981a11d80b2000cba96a622036f63b58f94d8ddb4f3f51432cfa33b2974823715f1abe0b372dabfad69579aa2407ee91aaa7563593254b00948128216fd3efae361690f87eacd013cffa2e55c50a49895e52ca16991ae7ad631da81892664084cb1c521fc0742dc0732e8a638618e22f0f8b2316a8759377f438c10000009028c973afc8072005b575c14cca6bb159002d2024fc4ffcf6b4a90fc443e84ebd23cb498ec0cd46685f730219181b8ffdfdfac8573904bbe98d17096d347c9c8deaa6f18cb539bc7222d5a59c22e775ce0ae863c19c6388afba27d1a35a36ed79e759572be92591b47a92751a88094b05136517e0b93be6f56e431d32b906963ffb1bc9f4f4e7b140e668690efdaef521000001bc00000090c251c2887e122e6cba8c451fa308cc66262d76f435ba48a8f121daded6f254fc8438a1a542472ca5ddb23ab196d7b27c9c268a72d3fca4421272be7eeb7087c09919cb789fdb12606d2cbdd6327caab62a917b9f8e46bf2c83ef29dcd35885ccc9a1b0d88f6e6f78cc419399175651602d67e05de51d75535fec4c7532bd1c74415ff1b41c539a863578983fad6e0a8400000090082cb812c86e14b312a3e43d8560a673bdbde8673d2a728f99cca2b9e7217344343028a7cec9d079432a06e139bde2933fc59f0d8ce7befe6d5a7dbdedf5da00d8b564af7a9c0f159dfe7b8247d0ad57296828fb7fc593d279b9ce9f48e018d69ccda7cd6d207582896bbd0be7b9a9bd280f371cd9b7eac113d7017a1f48e8cffd8991a9c31fb59bd3d609ba0464774e00000090d13cb195beee914e24b867f316ed0a00e1f93ae1dcb1eea05c989770703db9870b8eb3fcce0a12674a2112511bf7a36efb1db8d7ddce9d2ebaba71ea0c79c26b204853d3e1070283efce7cf37ebd775a2b3f0a080652b55c71d984556754bdc5e74239be9a870bad98c9478a5e1f31760f052197f58a5aaae91b6cb1aa03d8aa3d556dfb16780855c3d67ea74e282bfb000033a000000ce400000128000000906ced29e71559289b41a30bf1c8223f7f5e190c5da0f18e3f2fb36755bc81632a23476279b21af617e3d5816669148c207bcfdabcfb5b37d9b93055722276f28be39fe324bd2300bf8242cad86eeabb7205bd36533c669991697f7ac788acd5c818c25e3dddc85b52244d0f6934006afc1181fccaf9c0671fff329245645cf57661f534799facd0b91395793e958799430000009061165e7ade49c3d555e2d506013851883f97491a11138301a64c23d06d36c60855ccdd2ce6b090b52213ac32f93a3c1915aa511aed6aec6b43d4889b7e8e12e349e3c0ccf01091ed55c8808debd2a49b2e0aa4352517caef9be648a1866a644d5c3232d04955edaae334e4f74a32256d01d668ac51f293586688c588fa1248ebb561579b8f1243f64520d602928193610000012800000090c20307cce2ad40429fd085e166598c6e159e2d2daefc9987319ebc658f37ebdef8478eb6420ac9462237030db7d460732d3ad007badf7923d27ede59fd9b76c82b5af2c60804490219e0143d168ee1032c354276018ec209d3840905d6fe7ab1d80c315c2353388c17a5bb292d30c14e0e8ee38cbebeb040b1b49815a01c50110577349a069232cb50749456b8542ca700000090c21be279d7112c8233f699b86da220130309e45b8f46a5773a71c119a9d39a45eade90aff8ab2a61e72bdb611fc799af18a05b3561d7fea5494538ee01e558afab7aef60b0eb51fcd9394c3385cfb0d423c767e83c2e7a1216f859776cdac28b14efc4ae43d6b6809ef2803b18d9cd7c03842e2e13d817c95cefaa7f8ed91e974b80b3d6917a946f6158a19df15a947500000128000000900845864a50a47d07297348aa259971ce32c2ef15021d561bb24e2aa4647489223667995cfd6dfddea6f658d2b42af8b818f6475e82f5ec38e8ef254363d8eaef5602e1a2d980c9f63b765836b8a436f11368746c397c46f8fbc7f610383947dc5cce8c663bd8443557c0fec48692f8b20a6120da540fa31629ba3ebb25da26a1b03276b5d659e019f8e8180a54009855000000908827ea601e3c88179aa5542ad6ca3e054d75359304fe90253f421e8f8ac5de67ca855d06b2c3cd0aa5b78acd7072184cafb9178adce066c2632234f2cb23cb6a06ebda3643f9869e413a6a216e84a29626b1114ba32561c671d54188e45a8323ac4b1660749caeaf154469fdb0a98e2303f50239d3fb942a166effc3f760d630d56fcce63bc9d3a7970893e6d343800a0000012800000090de481777e2521e956c1a82ca6d0468c95986b1b49915f9dbd3544f74f0d459466e8ce587c90cafd599075436e5e74359cec9887c81eeebdf1bea8672b5d10802d515fd85efa7d37a5c5b674ce00ab3522687ee41199561092b7bcd3a1e2210a882b53b9f59423495d3c793244e74e11817a3f58b2142475971a0802b8e1ff58eaa585326eec00da9cd7a92c0eb41a86c000000903cbb053a398485e98af097d1176385ecbc574895fb7e03c83c3c7044c266ca84d8cf849b1a4156b401159fefea93ff8b773639ed58719f3128bdf37640081d1a824ef9e3ec5d9ab1d45bbf92778325df15121af58b9312e2d8e5d0373245187cd8d6c77e0b4e67fd1c54463b77dd2d750ffaf29df1a8e2e798b6fe44e593097924cd52d7154e5b2626f499d04914fc900000012800000090e16c6579c155574b7fd4636bb4cacdd57fecf1694d69c94e1a72ebaf773209bfeed7cca59b3079e09c927f5161c91e335b6f72fc2e7104a459c5c7487de91b25a3355d2112104d19a1f2d0e9fec930b717bcf5da750f585642b4d43d79b87f5d7d275da2ef7c298b7bf5195b920a35b42c8afed45a38322a802a862b4f9af3142eeb31b23c862c681a691fc4cc907d20000000909b8015cfe88f81f4f5c715774601086214f10d5818f9bd191bd3d2137543fc500944fa5707eaaa85c688c7bb34ae2cd0518c2264d332ee6c577fd4d4e882c5e5bd2f0307fd9ae842c8d1d939b29723a92667f1ec789772e054311d82545b5140107b8c0b986b08eebaed37672902eb6e19719f5332e7a2a8180e2fc99caf06d8513a8401743d728de3be3dc52ce8eedb00000128000000902a08b6f9edadfd9b077990874240766afa3fd95d83866dd22304f569e2d33b657152708e9f227cdaf037a357ab0a4ff600f48a30d64d70eb03599647962dbd00f48a9ca96f99b8f6ac410eef7f2bb19907eb42623e48cde44d97064a5e76ed47e6dab6666ff1ea7956f1373d24f533a922859a39dfd5716a7ab2c860d4a893a1344af599276cf2804a6e3fed4b0e89bf0000009012330421895d95a9c8f0cf59381cbd42f3139a7dcc28c6c4dec85ad38d95e734e1149a9b6389902dbe08dea922ff800d6710ae3abeff66941ab1ed689ea8bd6a0eb788f7831b0097f5571ddc3d0830841e178814ecd91babf64d7c096fe4e985f7b9661753498f3f394df532d7631b431cbf7f35df92487a75c12a15251f6b0e73ad9295364213eae0749cbe2fa3b4d200000128000000909d9e2da1bd1ad0b265e7a11351d74a82f053e95d414e3e3509035aa1adf722b700fa7a68e1329d9906c610febfee397c5ee613b19037795585a65a8cc9a13fada7eeb7e68a533b673c4ab1ebf47bbe791a59536bf864b0dbf29e2186e8aa11a9ae564cdeb8e53f2a18b63bae7ae97c200006110189dfa8b9e94dfff867f314a1fbc03bb9e59bfcc9d496b056ec1dd01f00000090bbb2748be6a328c4adc4069ebeb37c5398c1374effef708cbc40754ccba78d6da618b9d26fe7bd0fb01a4bbe3a7a335019cbca751f8325c8c66f5f2c4609f91544ae2f405881cfc6038402e181470d1c01079698e5f2e36f6bc15b2aa5b4cbf659524ea6bbe04e04588d5398ccd3683a048f7b1489b0de7411cfc7cff87d563ffebf153f08584d55e17e304765eca385000001280000009078c5a1db7aee3e9361e5ca420122cf5eb55ab9697d0b41508b7bb179e6ba4f62a90074034bc48f91bdebeb988ce5c675dd0fc6e0090bd38cbf7371dc3457fe10828ca8ca90c393070ab65c81ce1134a61393ef5dc50be99f0eec64555dd2a12753939ec2650923c39f4856d1a68cbcb11037cf8db800fa237d10e4d54446f81231bfc374e6f84b431a88858e591f6c0300000090a920fad261e56a1e0ec1e816594cb719f899fb224fd1288a995571079a700b9f424b63a4cbfab814c3bc101dcedba4efcc8a4f754b0bae9c2ba78b6ee6baa71a24bd2ef46fa1157c48128c096dc709942f0492106bc6c3291da53820067cac2a9d12e17bc638ffdafe921f98e6df37150f627b37f6a549fec31c2daf649bec9f29a608ef138c28334b901f5146b63dad0000012800000090df55310ecf9a1052b12c8ea6b3f325d7fadcaea956437c6a08f5abc9d119c1335975343301985023f32c95efed3ba647563593f1570040135e91958ec6f1862b8a4db97e9703fd417893f918854646f1054122d0af6dc2ffa13c6acd8555cb07ea2a24b033b8290a6437928ce57b909d2a334328988cccc41d72d176224de78ae29ec28e1f5933ce55e88978dfde555600000090d3cf89eef5bde30788ede8d63de64fa16540e0f32f7a2bbf695c4b625fd9ffe14df603d49a8dbcb2d7ff85079f80235d11597b266a416bb52dae66bf24e644ff82c535a74e465a84f3f4546e0242b23c02bd93a36ba8cc649501f6bf99a12bbe6c5728fccf668fa2bd58ed848085caeb2be3e1dd5887b76898d01a6db4e8e4dadc3b1e61cdc57a41b0053981250116b30000012800000090fc86cea3d4aac5eb7dca669d076b2fd061d00e48d28eedb6873afa7b40366e4ff82e26adacd233c8f001921cd3258045efe30bb813162183402a371b40ddb88c2935b78adc21554bf3f007e4ee7d5e9b18689e7b5332a1e05ab70856d743fdaf0fa9da120870cbf04d918a65f16a885a1c19e721585c80691c65d097b6c8c92a4aebd924434c7b6024de8624ece384810000009053ab5bfc42c215b93e1ff640c24d7d5fd4036074d9c8aba43605458a90708559cab63e463aa20871602124e6e36405ee046fe8e82341ab70e1737325bee25f63215e11fc9d73f2a808c0a9644216617715d11054eaf640cf796b6746cbdd3fea488418f52673b553d35dc294f69144c30779432f41b7f8798bee222abd4aea7d3e148793dc477f1c45f57ae8fb6d42b900000128000000905e6e31986ce58e8d566b22248dbd8e742e36db217b7ec9535411ea2ff3d76aaf3b3c3eec489e754063e34fbf5ead13001a5e6f97635565fcbd8a5783d63011e21a823da8bdf690eabd1f75f76879fbcb0f49e857ec71a4ce840e5b0f17918a3a6a8aecc7ae60c921f29bf9857ddcfe8a0ecaa592c24c54eeb37338d671f16c4d5004ba49988524f6e23ab69c807d36800000009012fd8d0c10354b223aaca3b96c3ce882dd6bcc43ea0e79427324753ec7480cea2da54c03241b79606f1d63c330d26ba0b345727e2ff0ee6f1cfbd88bdeffd09bc05507f80111d163726655a51b8ceb692684a81eeba49a4b4e57157231b8338497c267c6f1c184405e1a7d3b8d1561dd22648a8f46a9cb80d858f834a880028276cb70268d5d9427ceeeb5294f66b8f400000ce4000001280000009030f3472bb2aa4afa7f906870a30601b0b42da3696e13c18ec49a94ee262dc1b536b62055c0e05716ad477dc3389e318fe164622664f37818633970b6cb54761d661e61e5b7f1e64195d4ff430bd0d97f2a9c2680803a8a65763022365b7defb845cbab0db45c28f0cde6fd1647040d8f1d08bf8fdf52723a1aab2ad7dc880c9d5bf5b37ed2e80ad5c8d7f13d822811ab000000906fd356b5b6e84cb93c5e067bb5d1ddf99fbb95c87de4a281ca3fa591a0d04960bdea46a9577d1196df1408adfadf1c5ecb273ac874df29c7adc3eac64d5f9e1494273ff4b0aa9dc996532693a66ee85611430e5b22cfad17091b004a87acd321eca932c9e744d9af1543716240eb6853191cd9485100f14fd22d96dcb3f03b20314399ced282ee408fb7eb8d43db77b5000001280000009098132d107bc7c0a5d87728dd6fb4727647e2f4f2cb20fbdda9b9585498c5c03503050a145de389ac72e59fdaadbd3f3dd2c0d853576cb5840d5b0d3ef300dfc94afcff4026a65b3c0825a72017505e711a8c45008e3b5bced0c77908f91c72e0b35b985c12adacab86cf81f2b20187db0050248a789b024b3bfdbcb94b44bddea4e67f1ebf2130fc97dbd257fed593a9000000906108fbe8ea485aea0c3b9dee478d8a2fc395dce9aaed16e08e53b456b3ab7827d6d5a1973394572f90771bce09d05da2992366a7970ec6930a6616d6aadae93c6e2340452c3e46224d14932fc7ffa1a825e7e6b8cc504243e76fc6b52f05aa4830fe7f1e30befb0c6a7efa1f8327842815268491e75d595d08894a3cba7a8b310672fbf79d627cd13744ba6fe52c33ca0000012800000090a640b92d89fcb69e2c200102a972ef00aef23169986bde7e450fb2d0c9850d641acde236c581cc72761a335fec7b27a0fc2bda3504d8046f2a683745404cc5c880aeba3f16d61377fbb723aec4df3a640fc3d6e318f2ddbefad52e99671434cc4f17845a5e93a51487a0ff6b48c68e3414e70a9c45b26b02e540a93fd00d3be97eeb6af5c4e68d2ab48458d23de52a33000000906bf44acbfd2b3aebc38aab3848c867de4c3b359d01193266e6303df1f0ff84430eeb64a1be407b1601c11743bd6a184dbb78e5f53cdc8f227467db585c8ac477193fbdfffb1b4288cd197687bd1d872910cabf3c02086c10f49c414074b75cd589ec279e7edb1d0a5535668893c7341400c73b5350471521e780daa529234c8c053aae6b2eb8ab29fdc0ba78aa6be33300000128000000903622d289412b4951637f9e55a801d7a6a00bce377d288e36121837032f05b258f6921547a4c5b410f30c2125daa1546b6b8d336d82ec74b388bc719d3d34c72347dd83315b121dd320e3434b70b0de482f71e50f882bb1022f5caaad860fb6e2b3e843837dfe28b59955a7725f9ec9330ab23a886f6883f230aa74854695a30224d60e0b4f4ba5fe30c19ef0751ffc9e00000090b88847e072454264065439ed169f92410d4e4654a0b1f39832dbfc3be28eea464798848393e82534b5485828429af27e5166a794544dad0018a9e5d2c5826cdb5d0334fe9f9ef469bfcebc831769d5872c7916e0a8a87c44815b66dc08519b1886fbb45428d83772e77e5db38d44dec52fcf3be71a84b0bf17c080930c6c0119cbdd6ed061a2225d3f23cbddecd36ecf00000128000000904201e3550d2e1f76ba1068c82ec0a67d690c8e51fc9f68c7f36c81263d5ddb29be32e5e3e3b9664d9bf4c4363436e7a41749cc645c29150275f8501a87a0174371cfee4ae8df103d59b0d0b75d7ac10418654975639bd6b9ba06cbe79acb60ef3868b697ddbfd2ed661451d061c3a25c02cb1bfea7d3bd2ebc0f5f0166c649562e96022c6d14714d4367c4d3763a6f93000000901a4abf13152779f3020b104add938d7117f3efee81c8c129e864e087ead16916fbaf4c2f36beb51e706f185afe150cd005ca9b0ec51ec03757c1e43def29e24dcdcad410a5775310b3253db842b7b00e2f772e81f0d2dd8c3ab5efd0591d8d772994a9ca121fc0e601810d87c38070ba246d2fee20ac6b429c525f1528c4115f357457bb61c3109edc71450019e95b2a0000012800000090af135c5f86076eaf2ff68254357089aad9e5feec3a67139dbdc62da177032337ee03e6eeee03c5e017fa6da3d0bc05709006f68b11c277f52f2cddaf691d4fed83e9c46ba62d8189373724bc8e966e850458df493e3c8762e69154386f1cdf20fd5b1515c18ff7dd5e523aa1c167eed52acae16139da38501a6551c47f0743227600e0643ea83b830acf55497c8f519800000090af3b415745232d4b810cd1371c2662441a7745ee6e6899f0fe89dfc88e5e377f85e95bdac825a1d5a8970ae68393b432ea5c886eb848838701adc656330cc7cedd54270324c524f4f7dc46f8dcf48b0f2039a5325bd816ff3b57871e68f153cef59cd172b3dcbe700d0eb44d3cb5820f264ec501f59a78d4128c39fe2880ecb86bb64c4b093e4495ff680f110743059d000001280000009039fb70ce62c23dcfa825a7bf89053dcdab094f14b3d0974ff76cce08f48ff8f7b63497afef0b281a4f156cf0af29ad59f5d36e95eb80d825ea4697ec7f7f710c2b51790b45462f5f129310013071850d014b07614fc802068f90631cc7e0ea6b383e40e4f19b44bd0d0d7d522a8d121a0e275c1ab5f6f9b274ecdf8d280f9750173f2f434b994c2ece09999cb0501ce5000000906d2141941550893d8333f7a1a0a9af9baf9f6e737b71f07db67cf1283b4c939393986b7f0109dfebedcdc19c59e000febda964ad4ce208ba59ea2ef2182ee787e156a18ced9510e50cd4a177220896c716c20c62e0ee3803d408603fb34d70de2880847f829e5ea6c9e4255f3f53ac091d2ea4960b6a99c63b3d58056c861622cdadd11c0178d13fe271636c5686cde10000012800000090e6e105147c3ab0f1ed9f425fd0d8beab8525d5efe0a43872b36b8fa9154e89adb9437888d7c316d410cd9fef9b5deb1681a254986bd1c2be16e5b465af02349c0f01faa6c7331643c9a1ac714654f0a02a4b6ccd3839295344c5b4ddc939084b0d8ce45b9c922dcea2e7e62156a265f104cbc24622883bbcd114b3103b0e4e7b78c3107b2575eb05317f27eeb59bb35c000000909190ec9fe430c035ea72f17bd3bc0b3a970ab2059e32bc49c0a5ddb1d278738d7cdfe01e920411a977934e18824300c9d2137947fbb594137c70803fe1c9629022c3d6ed77c89f35d541116240a803000cb6f57a124eee37947fd8bf6f66cd67846f0f1f1576f522f5f96b2a920386ee208ecb88b3bb9412e3fac2970ceacdc5cc06cac0cf2089981ae0bacb3a1b7d1700000128000000903a28ec3706d2eef4640070428bd729e97b4abd3dab30b987909e5cca650600079c6b6845f201ac65c5a3949c408c2cde406b2d306ba688b65e3c2717e4edcb8b2940fe6f48fce8788c945fdc283b60c2208770380b05ecd318ab816526d340e1d44f0e4b16a7f561ffa26c28bf7779d4052acb479b576a5bbae956727227887eed77007a37954713abb709ff6531860d000000903b8a5676e83b32e7f978b723f1accf0b6c5f191876e43ae4983db637bb1af8a4c699bd1749580fbebd38cef2d10b258f00166f71b14bf35c1c98336cd133fefa21e3b89fdcba4f34858f60ff61f02fa51b23a65ec2bc0434af82356f00751b054ba478b4872320543f56f082435df8bc28a0fbec0d9f1699cf85fe79240bc01b4fa41934ae52f3dafd57db6b095e49be000001280000009007b21328b8c8bd7d2b7ea9db1c48deb7abd40e7e5987696d90d0bb35f3f4d8c4cf515da524a06390ea4c29a7581dbce23d174380038045d19681479f9bbe4642280605ee3ed024fc475e180e376f5558028d37eb5ce1a75ce746d5e5f5d64ef0f888006ffa49180ed079a8cccc22fc830a2b1571a64b4644671b35c7c9fed049d889622c2ac19cc8c9e666dde8f7487e0000009013ebac517052f806e3e8a43f9a76b3fd8014c2c51bac75c18813d340209a1f8f49cde8903283fa0f6e57f99538d34fe76e2c2ca622464b2adb4105235645ff068510094118d808a86fe0c57f9c0067ca1ea8d11f1d4981a817216886744bb09af6f1f9437d0d737b3bc8ab7a277669f711c767ecda7972525d468db22be9c49e6e82ae4d6b053d753046689f1f6095ea0000012800000090624b9506aa525b6d6889e72f9b026880f244534be16924cb6a1248e5450c770687a29c580c5b9ad284ed9273486a579b703fe1c1bf5634d2762460cdbeedeeffda11364f71b3160fbcb8a734b1ae882a25812144653da5a24934286afd0be45c6f1e0153fe509adc5d741340513a826c111df48f270168fa72ffa3775a9a896a782a7cfdbcec88d91f0f14942c9f0e8a000000908839817e7303ba863689869f4a68b545060e5cc4a2680c20f252d0c5dbdbb3213cca4f412c6f2b935e561b839d319ef7a33fa82bf6106110f3c90f0b79ce5f242526f3b84424dd0cb4921494fd53e50a0bee29198df55dd02a54dac81ebdb9b1cdf9889154ffa5762a27696f1368faea2b84a7dffc567c61f7c6a87e082aa3f80f6acc2f16f2b3d9ea54e26cee5b3dee00000ce4000001280000009025e4179a89f006c7561f2f9db9a7375bd6e014fa0478234b1f56679d353489b6c5f499dfca964211832ed03f51b1262b4580ac1e68a534752b47cf2f7798aa42da358a45a3a6888bdff7f174613675ab0ff2e00e2bb76111c569e761440794eb10ee13f6cf1130fa680adab60995c55c1b11b85387ded9cf8fbd255e97d80040b0de541173f02de16e87195b1293a4490000009069416623e8132febf95d02899baa57788bd46cbd1b46c1db9e3fe4498c32ddd372b59f8c80fd9787b3b7adc70a2e50f4dd3b79f8015eb159bd251eede3013635d72c8a105813457558e33262a7f08df21737ac4eb5b7dffaa8d8e4e2f0a4893a146974112f8c3d6190f2162b6f89928504e99551cad7da3198cdeab46290d4fb2d427dd9975e96b2cc6394c85d399ea00000012800000090fde0a703c4367484e2d7452c7ac078b8e59b36c449f09b170c5eb35e5c7407cb04d17840ff92217b30f280b7b740d265db469c41baa3e9bee4bb8767b552076866c77ae3af797703d42311f7f13557b71ac51641bcffaa56fc7bf4b851f155e0935831bb9e362ad98f1b172b3b0bd67b1f5d8e93e1c95ba553ec9d223ee8f3b20d32d8184115af308218d30128803add00000090eedb114f15d635863740f6f166cf200c9abf5a0ba790aeb48fd25177e2a05cae44be9925926537e7b0cbd199c8f5806bc01ad1a921c8aa22ea6620e7b48f51d462c708c3c1c98d5c6cd5765849ee580d1556612d0017c5824430b58b42b40997353a5200a369497e1182e990524c7c000b1f4445af9513fca8bc679754451e6681828d034f7de583d1f106dbb1576aa800000128000000900f5b0b1a2ded4152608ce8966a39171628dcb23a03f2184956b537f0920fd4d01bb19d06a35f2576b99f9ff31c8fdcb0b16455d4ba4f486ca92cecb091c33389517c98054fc81a7c9d648fcc62025b281215827d96434c2606a4416c11de6ff75a969a67e0548e8e3c36196225be2d8523de79ffd1224e59f5126287ccbf9981da6cf746853166c7b8082d74ed3754fc0000009077f89fb4b68a9f1ab542f23f2c45f77709d8b88b0e83a13abb74c9ee9c9b23e29943a931091498b1cbfbd4b219c407b8400e61ea0c47ca55dd8c55cfe6a0e68bfbb9c5ae4c22cfd85dfe79f0f8d7add12d3b87c82b19851e889f571218ccc80ad9ed5cedd60cd7098459ce34fd231dc01ce4dd7153efcba4432ea9dc48e1acdba76d6a232f720e5b3a0d9ef82c6f84940000012800000090658c2fb8283c73e49963439e6047e80cb73ab3159030a1e8944caef2d028af220e15f949472071a9f815af8ce3d8518e5ab7d1487c7ac1218af2feb9e452f65569bb0a76d493a651bbf2b07764af2396208a908d4c81553fc7b813074daabd0c2bb0dc5c404326939e243048e0e0f6582e75ad5acd36c0bc2d47eb922c4ea97aea0030b346cd362a15823aae70330726000000909106f34f3216567269f250a7aefcc379a5a5f73491308209fa4545c9b12d505f0b6cca6304b55cfd679fe153771d69fdc174e86d5505f7538f455bfab5027a14c1d0f79e4441c49783c3687580d76ceb10603aa326d144b193a05a4dd6abef19cddc19e5c484b508736bc5f6c1f6452e15006b0608d7b76d504041a888e8019e2b2e5d59e825f3bf803ec89863c4e95000000128000000908f2d66f61c398d081d91e0cc37b113dd1cf63f37746219f040f08f81183a96c411bd805993055d94f9a2642affd04150fad1022d51e4748ffc5904fc57d4a85d0d0b1684db8617b55255e327ed08749e1d938d69aef70f4a42d3f4096e8d1fd0c22fb303666bfa66851aa236cbcec42e03b1cbf750519018e1db2ad8e4c7ec8e79d8916c5d21d06efc4e497e89ce2db40000009061138607fc1233949b170ec2c0fda3a92bf355c5da9ee4b7dc854bc3dd4b99ad56250fe95b32d68714880174355a85b7f504d0e00a93b4aa951ead1809bec41c85216f8c1bfa9ee91b5198949c68066f0387d32bfb9df687e882e2434b6d682141ece88a5bb0d529e016f48bc37109301625b044c5fa7200b56dd1b64cf238adf700ff3ee89c32a2edc2a5d2bf483ad200000128000000909930bee5b317d075ba5cbba4c8ab537bd0878e00f1c9c940d39beaa135fcc9208388cde74f44f55bb44d8a6067f7867dc92971e18e71c3ff54868db71f73df74207cb533e3e02dbc669fdd5bf27d8a89042cdffa03ff863617453c97bc9b50acf0f9729a283057555aa40a1f364098a9033f9b3e622b53c73c8a2d6245b32811ba323e37832a36f314e255ed362a46d600000090f9b68a55c28a7b95514f66a48e4b03574ee8e7b633b11645223c6c59cbe5db9592d8bf0eedc05fb9263dd076d7a88da4fbaa717a80920513b9c334e10b650a51b0c1a126e3b258a60457be4b7f165b2a0eb7902766aeae1699361bca6a1b99445a75d424c26ec0a4d21032e554f2e763030154d3a6569b962080a19c54e0ddb70f9d20f42d97079bc47b1f0715d876710000012800000090b05b85d84802f2d9c7e94a96c230de0b96e6aa81841cbc29a6c9a1431956847e8fab1c3fe5ea8c24122ff0bb34f6f51fd13deecdfd683e06919463107b54a092c09d807c7a1e9659000af33fb522e0d72a502e4771e499d8363ce7862d905d871d39b05cc7cb5cd289ae9ef4e2f0b85e0ad7df39f1afa28b668ec85d5ce28bf2c2f471b41c24e817949648705eac1d9700000090865c148a995dbfd76f82090b6e7187e665aa4f003f76dcac21fbfda3f6d3e980de7bcf4e870443e5cb8c44d330fc5a45cc2d3b8f545bb8c3156a7d35a5386ab0f37c3737d5b5e06e2b03dc2b94faefbd19bf102dfbb7ac31e502ce4aa05e0160bdcad6f5825fab8c27edd151420a9e28076ef7c36e1bb3c12b183b9583bd82922437045c95d90b491c2872f9333ee35200000128000000901923f96f8868c7e823671f03dc0ad821aaa7d584a8df286c102ba498b76cddaccfb1be4dba3bf8ef4cc68083de9a2e0ba54d28fd2c1b669f98416d84f35fa3d6629d2931d033f8c95a6223c5a0d32da127b9c0b641a641663e9f18d05a68ce7ed5ee82c661cd76c42e2501188897d26b29651201b725415d5674327977266df140e3ca8cebe0cc52f13da6cb5e76ba4500000090d4c3cd035d1089a3d2d3d70b9995cf63418da271a2830c5dc8e2a6b5ce5beada4f3aa71aa102dfc35cbbbe7554c1cf9c5ac6127b55076f423d56f4622ffae47d40adf14d672cff3fb3a15904437111ed2f04363c8bc4df171323ead3dd793ac098acc8f1c3f1685628cce426731cde6f20cf746c1e75f261c9eeb8c6912e587ed851c5d706707429a0d61d4ae839091f0000012800000090131088d98cd6cf8548a230c77e0cacdd54169209cb2ba9ae8beb9880dbd0484f6e3ab7f05e8271a2c161562f25d0361c6609bd5d846546c1f7300f535a8b244d855d7a2b751d32a1629d343b659336ed2349d52ef499bd19e73f9675d0a934890e702cc522cde8f9decc1306e48dd0560feb00a244a14d299f4270f4c8bed06e32a898a234f0dffdb4316fa7e814726e000000901bd6fa36327143be4d65f1ea02bf932a7d067055279544b2a922251af080bf87b207108d9e717161e41721a8020d13db9e07d93293694e4e4ba5ae88062a0181a329db4e5b087710c88ca915e516f1ea176b4dda8bcc83229442089af7f7acb0202bc1b3d032ac0d9105c8c80e5817912546bbe34f018f11ad09f5b1505a581242fe198fafefca4b8e7eeea30c2d03160000012800000090b736f7b6e2f224b3e7570f3f494619ae872d055f6183642a4933e435823d1962fc427256a0610cd81904592ccd45a9ef4613e7da8d8acd1a321f32fb60bc041f7c4613b51c7ca31128a9c2dc9536bd6027766dc17e67fdbf5afaac90c495b9a3efa7c13e10ab3f2e0589039484dbbf60116225004034c411594e2b111b107e4cfa1992d75fefd31669aa06d5bedda6a2000000905f29189ba16aa5615d50c871ec5fd77b0f2a4611984b53cfc504136e06c719ca4f9f5bf54e77cf861f2b2a0aed8501987e00d38166b0855417c31062c7d093ce4f7d444c53e11af0f554da4a59c82966086900c174d97530fefc2250711d88f733f5b16bd73811077d6715caec15e928252b1a85ed3d33609e1404329196a570f911d28639bb67206497a9ca1ba5a7460000012800000090b9d8da40a7e9373882123dcb553c8ed4926326d914feb1f0e724cef1616990552da304f2bbd5ecacf60e1b4fdf6535c28089378cfd500f22de3d62bdf7b52126de23cbf2ea09d7de12af2b168dc9406c28cc0435297e5a7aaa2113ce7b9b87e4ff3d855349e974f019132f3d0147c029162c39f38f83f18d3871e47a20590bf5e2ce92637924ac32ffc8862f29db695a00000090cc99bb3dbb2008b94591505ced444fa0e0f5994d5bd1544fedc76d1191097cd612bd7bd45c2cde7010bd0ad788c4c78bbd75f91bcbb6cd221df3b22f475c5b26e5f3cdc905e04a95904246a3ef73a8972ac85096f0ef02cbcacc38fa329469080b4080e2a9f34ebecd578ae79c53ae7e2d0ded061af7fb0cb654b6cf6be7bdc4e0d641978f1394451d12ea190d8c5e7000000ce4000001280000009093e2f8635a045c41c8d9257adda690fb5beb3a5d56dfe78b0dfc3e02be2a104df2ae35d92bfacdc93e35a8f166d24a1f97499ce93faa066176bc1f06a73d02311507712cb1ce5f04c63e27bfe3c3e0651e9c2f13d5cebdca4626f083a8f36aaa65aae4c74d704355b727d601d2305bbe0a121bb2ebc79160f5c11a8f9ac2b69915824c413cc1bccebab0f5fb550085ee000000909bd5f2117634bc2eb6ac1558ee63de19c9906d306a91e434cffb75722aa6b2b2604a84e4ffa075d03226dc5045b16f71f501235820340e4da21c8b46c7b2a4e61f1e0b69cb985a34257c38569ccd0f1226b948e0f2ce68b0ab7849e9728b0517fb9890846f446661a335854e91c14e83302f87c6ce77d02db8e81bd3ed3fcd9dfc9a2c00ead57cf0b147b65512681fcd0000012800000090c0ff69960190678d193dddb5d32f220bec1e0a9ec238240925558cf7dade6be9038dd0039f31513a96a05c05cad1d883f492d42109006e18aba86c16cb6e0fb876a28df71d8e89fa02060bac14ef04cf0e1e34520905dfa33602d49a96ca766a2b46eeb514153c0f13e057ca2a0ee0ec24374b23c5fd922cb266dbda4ea04b879baff83583e3eeb12831fca1eecaf0cf0000009014f4354e9f6108f7ed4c06e8b6f4ba9040b9261d6d22b677d848590958d43a5507852f3acfb45831a25f4dcbe431ac979204bd0dea3f6623c04ddac1870014371581b84ef68f307342c25569987ebf9c10c8584ab1d72e995795b38b52ec6a3ad522cc1c9517e05154e8157b1d6f87f02a428d121d52569eee3bd8bdd9b330500e882390d0fad2d419755a17fc27213300000128000000901c0728fdd04973e9906fd1b541bff24461f9403a97802a8129ccfbf0bbc7cff8f81cb9fec321e2186365860d08202bf3f7168a618eb6342fd117c213d9d6428fc1537d3e8a01cd4fe21c0442bca55cbf16f3360c61254e7b2d089f38eefa4b283d540cab1e674c833f6f1d98b39369e92989531b35d6e006557c2916d7cc7bc5df35be0d64c8f497278ef232d58093a900000090be5eb11fcb7229bedafb364856d9502f66506f9328fd44644880c9e8e183ae0c861b7720b70af77271bc72291abab5963445b8be8ec35a402f5b23efc77e49aee0b6c65a99bce778b5627b5fee60a0c42d8c9cbe8e39bf439608cff529602ccd005c151987f7bdee3a2bafef9e0dc3122b46d03f266625d5ca0895cc527b6fee308661e23c20639c9bdba02b3ae71c8f0000012800000090ea504b252805bac5de56d205a6297cf38a90d101aacb4538f26a41adf9e120494e2daa93318788a151777b0e8fb5e0444bb0de040f684b48e113a3bd7d43e280263fb782adbb690053923bb0eaa7c0f11d89cebca94e1077de29e1f13450017f2d39e5da7b738a58158467680b87e8a916c6385cd1249ec51e5e2922f249b107ed353789e24e45208805602f96a432ee0000009009852850c074a233370d7d9704885ebbf57d13ddc416cd3809d7ed1591b05f0716560e8328f1efd042a4d1ade629ee9b693ae5866fa1f3970e2d91f41a03250126330bd6e27fb64bf6312c7600770f542be1632e295fb6d9fe45bf91b1030cd0c3150fe3f65ab4d1d2d017c3839898781a6e1eb8f2f4032f4dfd5f0a600ef72662986176bb14b4b7a9c99f66f429106a0000012800000090b9927e80cdb316ac5a9e7d5aefcf6ac01d489ede79e20af58377baac0bd74a49f19db328daeaa5ec07d4ecf7ba55148032c4989ab1f8c30d32cfb74d7a10dc6b9b3b62dc7a27a8db24688e5683038a541f38971f13f8da2bbb892e010c0ef93df1ed8b7a960fe65e7efaf2f274f3869c1afcdcc299eb2080c41e9c5676d524195e22e79730f662f20b04c5c640b233550000009080bd76f074f19aecc02adb0d7b30514b3878b31726f96fe25b68f1fce3b3b191d72f4139d497900637e2c28643f24f581949d196949acded4c29a8a6e300769e5c58d1cc5ec8ccd76006ef4c20d700c01747378dcb6bae7af6907dfc8ea88a7c23f4eb3d32f33c6da243702b6f1cf7f8155920309ef26019c05564716d2c55381a86bcc98712c7a0295832c9770eda20000001280000009011951b508ec3fc32865cde3f8b14e4314665a92561b35282c4b5f1261ad1e28e881900b80d70dc13e96680a528c997f09ed77899928a287f17a8eff3bee09a839f851153bdde9d1577a89c9d48c74f6a0557849194971f6237e73fa31f725b2a1a878914521b094863164d5f5891b1300c41c7999762752ca2adcc89de07f4e1d9b3ba5a1cfef2204561563c5c73901600000090ed0097c38e390151b701a7ac242f6e73c79fac1e0cf1dc2f66fb29c6002e0f6db13a6d6027cf18c4e6308caa17da58ca8d48acc59805585ea6b006facb44654f6f754f9725b685bb5c4ded4de2c690a72aa7923dacd13f83722f0893ebee4b3ee8ce7b8a643acb94ed2925f282ff0c4818d6a0713c5227e13b9e28e9b58cc913d2e66750c5ac23e16ce76598472d6e9d00000128000000907c0e86120a5a037229ee9c3a6ea20bf194396f08ded24d811339ba90f1ae02744218270e0b2f3115ba455b5409284da7031e56eea2eb96d1204eb02c2e6ebb8a0b4f3e98847607cb6b2279958b0197e52ab0e29034302cf56b533d3157b5a419665e50428cced5f15097cd3ec2ea34951d7113c4a2fcf976adc69ae623c2557c19589c89907106001f1b25d2b7d9537c00000090745e83cd5102da600a92eceb7c2712d2ea6704b8a2cc7105dd788ee043cc0f0b23077b5607903c7053aa17c4986e4e9e8c3c9767070b6a814e6e4a89c904b12308c11a09cdafe6faf48b2630e8ad24552d5ea409a7ad8b4b9b117ddb852d61e70d25b30f70d66e0c7907e5c16c87376209020da80311afdc646841e86b55f89c920bfafc0623fd73585eff854c10ddc20000012800000090a626f21ac7482cd903148ee4fe9fbcb0bb37c2b0c25f78682b40d2c65212b9f2907b0d0ba6b357ad998ac2dacdb23a6d626ea1f240967b92a3aa492b6bc3f09a57242e4d2a8d50636f6761ea8738488b0c19b34b570e8823b97dce37517dc9b24639c7410183ef3261a85fada34c0ca510ff73ada4daacc553482d68d672cbb3f674c8f2f0751a37245edf6d5695557d0000009092b9b1bef2731730812331aadc03fdc1aa7603e10f72def23023535b475b25182ef02e5bee562306197922453c7e28c323463902cc16a0295d2cebd6e1cbc85715e8dfa9c8d9ab7ac810e29350360bce02d3ce1075f6198042f4b657d834594564a00700d5e457e7838a00b590ef55550b5893c4bfe5f65fce253caf7141e83111d74368eb8eee18004964feb64dd8bd000001280000009011c36f8adfbb22c9c3d657f7564ee4eb30d37fbd30907b2a0561bdad676980ca96254999cba01fa8050a433a1d0ec2e49722eeb016279c2a51469725498969edc938823df02655a402418f3a6b8a28c70d5d89a7532bc47ab408e4a634bde7976bb2def28668d34b131909defd9379ef0c3c1d4294e1ff613c7423ef3b6e575ee39591b9be108055714df1789da636080000009004dcb05ab956ff0b68077fc113fd949ac3fcbed71a7605d42c3a09174a6fd573d4f66e407e468a1f51fe670b01928a1b93179fee05fd11b661f14bdd6518f61f5e0bb6aa55060e1b8b3a9985cf9049c41a999e111b4a3c3422fa6a55fa8f0dfbe839a4d5f51213c3915f1f6aeb85c7d00903b9c405878112fe5263e476101e1b53a2d2804929612759e2b5354e09ca4c0000012800000090305141bceee489d00e1951280d90286be9dfde8a0c23e802490da8807d919892fff6dc32c9a66663ac0762043b0eb2376390aa1b282bae4d337ad9e6f41d6720ee0f3d0315c1e19b81fd2fafae61de5504eb79685817659363e38f998e7ec51f77fec0f60474e14b5ba3bbe63bd3874a0dafc5fcae9f9258e277597458fdadcee0e822c56a55248acb3700a463154d69000000905a754dd00b1c72387b2b59bba5fe3ab77cf0a4538ddf9f8f658db80c6ec2a1327637e5c05e9ededd5d4da46f842feb545f8eeef74fd5a5a214eb5bc46966c44040e5fd9d2a87c2b15042f987923722a80e7d3a43fe74774c3681b1c792a34fb0a4f5de14e1c6f5af9fed1dea7694dd6c296d23c677c781280cc6c2970227eaa0ca6d690d1f738e8ae5ca76bad02a291e0000012800000090988af0a1f57a9dee97278df9b1fccd62a21cadfb56160960eed6abefc95d5f0fa96cc2e3bce75894bff947d855309e264c75eb95c4532de49e810e59abc43ff98d08fdb9e3b0f3ae561e033983c7ab391f521efd6af2675bea296cb4f257850de0e3ff28205b935b76b05d3584222e0a067a336c8be6a365c107fa95959563cbc11a1c2f63914d41bd5c4b0c698b0d2f00000090674e68e7621622e4a22d90d7aa2a1651bff1b53bd4b9f74e4da2c3a4bdd05513206950613958362efe44c16cf3d2133419737c395c0ef4f04385ee580a561ae1647db60f3da047b382789331edb670be103fba6587fe6f26b1cea9bc26820dcc65ab1a9023fef37e8e52f0cdf5fc69c5083b8f5855fe15e138af8136188b9b0b2d80aa2a60b895d4bc1b0ebe0e4121e3", - "calldataHash": "0x0ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf41", + "archive": "0x25363e47eb431704f0a4b33fae75effc7c34f2591315970bc9b3adaefd5780fc", + "body": "0x000001000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000017100000000000000000000000000000000000000000000000000000000000001720000000000000000000000000000000000000000000000000000000000000173000000000000000000000000000000000000000000000000000000000000017400000000000000000000000000000000000000000000000000000000000001750000000000000000000000000000000000000000000000000000000000000176000000000000000000000000000000000000000000000000000000000000017700000000000000000000000000000000000000000000000000000000000001780000000000000000000000000000000000000000000000000000000000000179000000000000000000000000000000000000000000000000000000000000017a000000000000000000000000000000000000000000000000000000000000017b000000000000000000000000000000000000000000000000000000000000017c000000000000000000000000000000000000000000000000000000000000017d000000000000000000000000000000000000000000000000000000000000017e000000000000000000000000000000000000000000000000000000000000017f0000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b700000000000000000000000000000000000000000000000000000000000001b800000000000000000000000000000000000000000000000000000000000001b900000000000000000000000000000000000000000000000000000000000001ba00000000000000000000000000000000000000000000000000000000000001bb00000000000000000000000000000000000000000000000000000000000001bc00000000000000000000000000000000000000000000000000000000000001bd00000000000000000000000000000000000000000000000000000000000001be00000000000000000000000000000000000000000000000000000000000001bf00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f700000000000000000000000000000000000000000000000000000000000001f800000000000000000000000000000000000000000000000000000000000001f900000000000000000000000000000000000000000000000000000000000001fa00000000000000000000000000000000000000000000000000000000000001fb00000000000000000000000000000000000000000000000000000000000001fc00000000000000000000000000000000000000000000000000000000000001fd00000000000000000000000000000000000000000000000000000000000001fe00000000000000000000000000000000000000000000000000000000000001ff0000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f0000000000000000000000000000000000000000000000000000000000000230000000000000000000000000000000000000000000000000000000000000023100000000000000000000000000000000000000000000000000000000000002320000000000000000000000000000000000000000000000000000000000000233000000000000000000000000000000000000000000000000000000000000023400000000000000000000000000000000000000000000000000000000000002350000000000000000000000000000000000000000000000000000000000000236000000000000000000000000000000000000000000000000000000000000023700000000000000000000000000000000000000000000000000000000000002380000000000000000000000000000000000000000000000000000000000000239000000000000000000000000000000000000000000000000000000000000023a000000000000000000000000000000000000000000000000000000000000023b000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000000000000000000000000000000000000000023d000000000000000000000000000000000000000000000000000000000000023e000000000000000000000000000000000000000000000000000000000000023f000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005590000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f000000000000000000000000000000000000000000000000000000000000059900000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f000000000000000000000000000000000000000000000000000000000000061900000008000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003410000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401000000041c72e330b60e0052863df88b19ebb482d412b0a7bbb2fabb9347be5e59453d10078d263242fac5a2ad544b5005bcea367ebc04e01ff7ca279650bc63d9488ac304ad4d395e21ea570da47bf574569c6526312c5c7ad63a6d248f694e5c81c2b60e12693b411d9eb8f564aa43f4aa14e3e30f8574425a6d6491416332b77d2709000000000000000000000000000000000000000000000000000000000000104041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001080818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000010c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c10000000000000000000000000000000000000000000000000000000000001100010101010101010101010101010101010101010100000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d10000381000000e00000001bc00000090faba557e0ad98ee2315d96d69c82caf3c25a4d10cf0b72243facf67382d645e8a1b81a599cc0533389aeb681debb86d835c02a49d90c37438bd136b96045f9275f23fe0423b91210b2916b3f57d50400028183c068d003a8d24f139221841f03097934d15becd319a07ee27707451b7a0c719666509d3afb2485f646dc58a81a529768e50ccbf4273fa2e15476d37e4300000090a38fb01df8082d1058fc5fb9bbfced55f7509541efec857c25e9b027ecbc9086b2c05edf5be370c8ef3a808e13c8974ec9f1efcf1a6dd018f5e146e4e652183e96e5c8a41963dbbded5ddd932ec5fb3724345635ea211ec2a812f3f6f3c03acac7b5ec8c959c79c4b665728941fa1c0823008a54c68f8d98a4403148f59c6b7f01f487d0a15b66e91169ffe7505b01df00000090ec23ddbac68fc0541f0905c259baaac1f3c275bbf626e0684c9627489ae4637c16dd7edf13ace12934cb43beecd7df96120b0a445a9011f1fb47aa3155ed91df448e04b6ef5082495065b9d6498bdaf5222ebd02fb2bb6927b73c8fd7e1fa7dac0cb4ee59e3ab0929b295d0f098f2a9307265eec9e7618fa7eb0661bd24edf0ca42207842332a2921bf33f4b890e135a000001bc000000900323e0b7e5571e1800425de4ac2accc93e0c4daefc3ff84371de9cafd0e25463990e8255fbb11ddab5e4a9b80fc6c12d3563bd7e49dc971fd4e9bb69bcab0765a05dfe9e60aa6ca559600012cdec970f00bce2ffd6fd9c05e7b93dd3520cca8197696eb3a8e050f79abdc37550c82880217f2f5fe9c39e3a25e665f0d7f07a2132f9e8236372a36af4652bb70fd028ba0000009072b0a3e5ded332dc63afdf5ed66d35b98df136922103f1e457d3cbd1fe0aec5a38147b024deb433dc599f7caee486612f788ae098ec6160bb16c568779b58b7547db7731e68d6a2b4f7b85fae53b876309750e5891e2da92558d6c65c3602776ca77203a39a54b9eebf207f84a8412ab280038bf2949a61667f0ff9074d68760a47859c00c00f809f2c8785fcd2ce99b00000090ec3b223d145a9291510537f240f1f5a389136eb53fe32e57decdee50cf7867682747186d5204e0567139d5bbb890b67feaeb268214ede3661d3b30bd7c3e723b5e73537def569d43863d0fdedd650cab00bddfb50d9fd4358cc1d8c1a66a1ca3b593e47f5e1f9e23456b944a2b682b54264bffa4aa99eb3165e8401c5fca7e9aefb7b6766455ad265363037a159f1354000001bc00000090d0362401429bf597ea4e0d5f8a354baf82843c12349bba64ccfd921e4c9fc16f672eea4785f2ef452372a7d32a0d5a5e0fe3ccc3f0fc53fe00cbb8cd5b1222020fa988a277ec87401d16d346f655e066263bdb07dbc3c3b7c34617399a233c1430db9995c669798ef408c2c5705b58d301f918ca1bed831f9ee6e67777da012932cc4f8798b51679aaae46092303c1cd0000009087f90d8fe894585f866aab725e6e58406c485a8fce92dfc121db621a30540e7d38bb88d1814e36d6d5c58aa41b50943527ee71f6f06860b866e1ad4fdc04a3a094b4f0d82c268a70dd4ac6dbaa7bbb062faf7999f49d82c25925674e0537759c0900e1a18bc6878d96f96501223fb334022bec2b5a7d99a0c5574e0195a9ea8511214480c64f8e96de27a2a82df656cb0000009096eb7fa42018353e143b36bce2a3356f3ab2608e3e568fd1747f4d82b646a271f7210673cf7f57f873bc295236865c43e6eff138695b96636da79db526f2ee7b912c201f37d82e680d31e7e30ab89ba51c91a7f1ecd9ecbf9df14830e532d5c61afe2261e8d91377dbd4546e3533c66e036ee22b0d0f8e9239a94b8d2a4cb79677f4f1cf9000a6699b63926c68c6f035000001bc000000905367848ef56aca2417cb4fe5250b356f593d070f574f71c120a7170b2378ae6a5e1aea379090cf3417287ba3e209b669301ab6aa3b37ad97e2a0d8e142ae6ee44af60ab2153b976ebf3f96232411dede0dafd18d2e8e86ffbb8c570f085e531727f4f7c8c382a63726d2d071a9f980221ac050936e5527648fbedd216db31f334e1fddea5a3582ff37d25b6ebb180b8f00000090973332b09cb17f8d589ba107484cb967642d280eece882eb9f2060cb0e7ffb904ead9243897e1d74161376a527bbceefb1bb6fb46fc0975cbbd79a28742b964f8de228294ecb5564d8f3af688508ce5209782d26fb18e533378d8fcda9031591d4ac656283a6c36141c15bf136e20ee628f92c331a0e02c7c922b34491694b0ff57a0f730ea1d2d01e1336d55f3a13a800000090388ce03b93385a3cbd8d1054dc567140a4e8b25b6efd9a3194dcbc41c376253a7b0443a594f99fa820ae7dfe403a2bac11f1146e413ad28a01e05b639e1f693bb2bf65f34cbfb6da7e87204c9506db4929f7762119efe7ecf810a425d1d309ef407e707c37e406b204c97df648b8dad81b946e3ddb836c5093207bde61603be7adf8940067ca0e9da6c4e704448f8cd9000001bc00000090f3404d1e06f7c02dd32c084c5b9280d635c0fc243bc6e8e9b930693a8a2e55bb197989de1394c64d70611988c67ebc443fc418476fd6cfa1d63f9a1358ab0628d05ceffa42577b290069b9ddd3b49d6704efb8a3d89a81c774971611839795edb689e9f6ce06ca9424f971d8ee7421882359e2cf95438a0d0dee3ed70f87fdac245181dff2117582dc35f25563d8678f00000090f54c8cea6d621dbdff96eda0d560d17355bdff5620034ded0f79242abe7442f5f7327ea5c7214e622f444b34285cba54b465fd9a301f52f0db8cfa621e8789bd4dd639397685df4e1b7c3433e4da5d292fef8183cbb8a4a5c5bd364387d6bca5f04f61ec63ac90392cda925669181f37062273bb2a030f114f914165a9dd1fa471087454dca6fa0f72ad2523e80205b0000000904a65f0253b8bee3dee6468d0990c7c8d7c1a1d701d2bb05530e207bc67c6857ef7ac993c6401b01cebe4d428ebb6339badfbca93469ec5819aa624c79af29566442906f4520a162b49b434de2da2263a11934ff8ea2f7f9c733b4fd9c9f2a53dfbb2ed48e7204f6e9678e15972212cab16094fbfb58e358094ade8056abcfed04ac62bd9edd4884d5dd54e1b27bc9d7d000001bc00000090421ac60035ea3973da6ab37ff4cc775d3071bc4257bb79fd89f40fed05839af3bdb5692bd0fc8fcceb78050381ec004f8865fce649527bbc3d0ec27443d7ce080beac95a9bf0c59c74f88db558c22d731802a67fd5bf273582f6d1d8cc881b1f5beff8880a7f24a8141f99c51b24087002fee135d67ed43c5e154e367d28b4fb01d9b1a651f720f00929ff6f4444a18300000090c729c355dbcdfc5d1ff4c906f9d6737673cdae6228eabfb506c85073be6e699bf8cba46e03bbad73b8b3de910424f44bf1fa4b843d2a2712558698ed8f7be88f11fc21544f0e6aa45479c9863b3a64d61f95a54ecf91d7f27689a919aef3fd3042b9ad97f45d4c9f008eef362f4fac2a2295ced65561420be23d31cdf42d7c63cee5b36945b919526366671d964e851c000000900cd889f68e6227eee56c73a37fd7f06e8031bd42e784c919be17610e9e8eb2c231c74179def8c1bfbae1590978c7f949ec9180a9dcae57933c7de0b292b7a837813c7275d082f420543a162b0b82d58a06bb9d303746461e01b471e19d71e670541ac94e15d6125a28ff9e37ae0a7c8307570723e17b811ab2c0a5bbf97c97e06614d53ec02d73475629711bcfd7021d000001bc0000009020ce73da267c1ce22abd868a5f673da11fc67e08023d821070a8709bbfe6feb98bd19084a8674c68590c787dd5f442ec18776d391d221c7d4d782ecf3dc8e7b14e001532f1d922995754c5de7e03298a102c62a436cd1468a6d3a86a9d7e711ec2a23de7e3f2f660213ec3490d80138e1e3abaa69381bb163405df34d59fe6a7d91f16a787192841d17389af4e856eb8000000909a5924162a4ed7a5b8eafa9b8600170c407987210f2696f70c0e749c7e3b4d3049c108f7f5de014075783e0755430e5a704c07bc1821d3128a0e2a48a457a4eff5fe0ecf5bf04919ed582dfd459885011cad8e0e6aaeb74e435fdc9b2df0e53e30d60f44047ae9a181448572615e9a6e17d49193c97b65c6faa9969a2a67d2b2fb6b743dbe1ecdff6e4af346cb069a11000000905226e91e7e92bf53cca9a393340d168659de09970b06caa80da553281fe8bb8873397fa137e8c0f9afdc2c8e6dd439bbf84fc1e496cae7ff7c392bd9baf8adcf4e732290a4d18083c7ec68803b373fd4035e3eeea067bad11dffafdf132ee701d0640c4421ca3c7689f91f1c5450f7360e0c7aff83acbf0ef3ab2534d58efa80f917417788d4a56263a097dd6b9270fa000001bc000000901aba3c8913e4421e9cbe9a08bdf6b7a977168b9da9f7306d076811e1b292f45dc59c58fc5ddc24c42d8b45f45eda68911e9bae9122093c231ec898dd2b9fa94f388d65fa55585bba753d2d337c8b0b4a297b494af2f8f5453dc052fc5bc9c6d56a4374cbdb2d090d5b82957259154dbd221594d9c7057daa32aec5289317ab430f242c6bc3d71311d52c640c7fa89b4b00000090db1ab6330c30d19cd86089bafa5e4dc6b5d6a814911e97b2939164cdf3c69d13694c4ad1f65921e6fec11871ae70645e992550e3f9fa5a843f1d1a73aba45a677b2b9ce39ba23673122554a9f78e43d313e21f567b40a04e0ebb3ccbc7c7ba6b645488c178c3ccb96cf51b84104351152fa3a46c38eb344d8d3b9a56c2559944d3d3d4189d9565c489587c6ab916d22d00000090ddf1320522d527312ba41ea1664cdf8016914d0d10a4b4ba43e993ba22fc1a84c13666115f065c7b4ea954c23cc99031dbfbd787bf2921e2d678614075a3614ee449571718354b079569e759383162e0151398cd985d71c636fc2cb66403d35dbfbeecb21c0a63efcea99ab3fe147b682c1355e8d2646004ed7532d566e577f9b87f656cb5aec22a9a287ceb73756cf700000e00000001bc00000090db652aad22b298bb4d19d8e27e604ae77a79d0be72303ab9c14f2957483f5a943a1002ae52c2a85dd4566be96d155f1a5a826ede58eb4d15caa27e161270d9aa0959244e96ba52df5c3ffe468db5a1e615fac3ba85d16d682a7c76b082c2ae9bfe826dae62cad5f2b8d84049eb28250b22a83ddb9041b0608c7a6fb6454155274bcd40aed98d689e421fdd1a9407e7d20000009096d465fa51929c45fdc1962d72b9e970bf8cf421752ec92203723e30bc6f0664ae6479e82a5bdeecf07ff3e35060b8453e923dbfb755cfeb0c26c0449ef64d22c260818902186c55098a0e373c9966a400bdb1fbff98fa32f5e38b1eb2b2a998de24bec2ee46bbcb41fcd9ca975564080b038f1b8714ca33c5b5ccb48015b8b90600d671044b6b0edaaa710f71ebb300000000902c4ba97f0ba9a5049abaf70f75e1ef6599b1ad849c4e250044862da169a1acc09390120a63048677fbdaeae6fd240ef78599e6fc26b3bdc44fb06386550ea0e250db2153d6b228af21a83ea4141590ed0db491aed405e08ca217d27676ac8f6e2aaf151460646a96aed26cc1555e9fc10a333876667efbea046384e51f9fd09e67c2528f0882e7cb2d9fd6c00b948bca000001bc00000090317d6c1afb0608d68b98b037fda8b2e756d35fe7a4289254f63cd5271da1030b82c900a9633871d3971beb7d7fa0f22711d0245a1464a69e150f40618aab87941e9e64ec3f9350103f6475f7694eda1904e3d9e70b5cde6cd9b73af29e841390f75d4635fb9eb60a619e90ad7cd5918209837b1bdd8dd9d7baf1d8e353c586df94cd83476e6ec019e6160add6cf9921f00000090fd77b23ed79cb12ae351a9547dfe4b55a9caa709c08335ef1d69e490a66f2b2c44269e30c0637ac12a163ef780fb498939ff599edd250bb2c0ee83cc7ff7ec58669c7672709808505cdba7f30f3b257319d474d29821fe905d9ebd18487e81ae7472c38f9162208c203ff19b14d33ea11c683db9703fdde751870e4abea2b2d6bb4d58564b542df14cfa94bd33a70143000000908fbfbed9da48bce055f319c2e430127104afa36296c62aa90e1711d964b74e3b8a69467c59ee9008a432f57efc5d8d684c478c67d3450490657e2cc12815e0a5e4a5a8b902a01f97ba6ff86588f317ec2ceea5bd518f468fefc6714f8ef88d17c9bd085f84515e5be766a1b1ad7d8c3f1f64726222c453203cf184b7df509a490b6f816a5d4802cac593fcae623c1f37000001bc0000009058cbbc2490d32ad9ce193728024d7a15e493e5071ae05df2e4c1cd4a3bbf75f7f6a7f1b4fa8fa35e65b2d9db2545df8ee843bdbee1a59a67b24de585951b51656433dc997deff629c8f464790b1a85db1bd987534d371292cad9bf458d5b9c7368fbcc91a9808743bb65a28a91a60c96212d4bbdf4c2da6fe1a52b88485221e0b99d8e1a2ee9d291337731a819a6b38300000090050147da44717c542c5c896f64820aad88f0fb619044c49519b4fb1b42bdaefeb28cd8d2fc945c93d8fec17ce89a521647b8433f3b2d6cd6b5715c871c4c74a39ed3fbbf7cebf439825cd62f6e7840251b75b501c5cb74f0e096d38c36bec48e843751ce33a641f2072125412fe76dfa1c7290a9086a877bc9ccb3ebbe00789bcb7c6b951cf9f7245184e487e8a86791000000902b67906fb61816d7d4f88b951fb2ef7bc51cb7cbecc539826710ab54f4067d37313586cf4e847b602f075c447c6e5af5d9e056f3c68f8776b4d7cbc2c7f5b0f487d1de9306a3a6b2ac21d1afdd30213e00094be594ea9b1549344219396e546d7df82c3a4b6231e4bcef8b6eed1fb6ba0352aa82a0d4e0e31cfa426621e95c4f1b929dcd9ee58997a89461275b7cd46c000001bc000000904ea88144c0066ccea172d2112eb0597f561a5948c6eecb78877b94a022decb1e14718d3bf395472454681a1a2dd1232e5fc53536a5ad7221ec7dae62b30039a33391239dc51968c656ca41f94a5b705216e45162d2c9436b1f5565fc73ffad5af006b993d81f0b77ce3fd5710ce71e1c00ac921add5f109cfd3f3e3900635f4e67ec4dd848667e066e3703ce380fcfc1000000904097191765076fe167e19a0845b5c872af1902056c1f01c30550cae7bfa23e762244b9645125c0e627774b95d97dd10d472f4857972211accf114f6b1452239ffa7a0a1bb2a8926e1e35b1c1e0acb2911b25e2c9cc1233cedef0259c2dd95d49910a5c7dce0dd73da9230cf313c4253e30135886c18941b5458ad482cff51d0f44ddd1f0af6b50be2d002f339ba1913c00000090b98ba97b9678e3b55afc14cd7752fbe96a9deb68965ed63adc6f177e17e082bb8012b2de5dc7ea2a30dbb10cfe30d35bd550da6769e343504a98f1c7f7df3a63e7383fe6e4412afa9c736e78f24525ed2314f1b6b9a919d8d2e3293ebe88f11e4d51e7672ef570cd9372e533d33dd656091ee34540c4e533b918dd513db6afa869147f1d9019fd18ec8368542a2bdacb000001bc00000090b0d51af3f81d2cceb508a7f1ff4d80cb8e686854f5467aee275fd23e7ba5364f98d51aa403b36ed88b25d7805c78bdc7f3358bdb2eb0ebb22a3d565d2950e61a3a422488cde294df2877cea73aea2b95189b6ef982c99a1c231c55770b7df6a9c122caae9731edc1a006e530cbf48f011a65bf1421065a71630fe13e703f33dbe56c355873be0876e5ef0bb62c892093000000903881a3c58eb83d1d25b2f22a30df0cf64d11c02edcd1cb5885fc616838dca27ae6c5e4cad518c328b5800212b2bbb5bc81cf0deb0a6ebbb216ca3d6455e4f941e33f1be46c11d52edbeabb48b38120ff1f875b221a884a5816af98ad1585b2706c842062eeeab1cd1459a1456231d0ef18cae46a9f443ac00605a4f854fef1208361dd754edc06d7fab2d9e5234f9dda00000090e76732a28147572bb4526e9d2071e459ab57d8c062c02cb5bcd6df2f41c2278510227e90ec5bf945bb4cb8efb2252ad60bbfbd9b4588eb30f279df077bde5ac429c632d222c406acc724c99291e4822e2df0791ddb5127215a61a1b46653f7864d656eddf3626f2f32ec43a0cac189a414ee8ab66dfea01e05845acb7158362f11cf322768c651e9d224b699e0c2b3c9000001bc00000090a1f618ff9c3f0a69611a72933f1a37eda13bb318f7020635219c6c2596d9cdb1b20f4d7ed143948cb5950c2f3f4648a616c0ddebbb95cd1025ce49f881411e9e920a663f0fad95fb42e0705092ad96431029d75f145a0d1aea34721db49a65b9c02a9d3ee1affd4acccef81330cf95e60fc325cd839e15116699e0eb4667d97bf392924405699916bcfbcae1b998029800000090c0b46c2855b8e0158be99aadc2262ef5910547df7fc25db2c7319b6f0902de6c84e996c3a97e056da82773cf0ffac13e10c9151027d0238f8cd7efdc782b942ffe748c06d76ba43be90448fc08e6ab192807ee3b19248718eec114232c6daa4742332020b9cdac97a479665dc391d49706948b16686dae1810498ce9d02f818dfcef12f3ed13e9d04b7664394a23f6b600000090ee8160446c9dea1d8d9e8f2cfc4cf4c2da6b22ce197a5f1a6cbc47ec3633101de6a6803828c9c507a5611036366ac58701194c4cb3e501189653822eaf6e57baae3be9460a7bfdd802f925761c79d24f2ea5cef0d55f8aec27ffb2568c9c48ba4927da06eb6297628f1b11b9fb329c061c90d24e6806d40409d0461fe26df0acbfef7120a88e2ea451278f2bcaee749e000001bc00000090d7558a8e02ae20656596a8fc7a4521def5c54ba209d4f307f99155c1adb6787a6a24723b86dce28709e82726ecc00f6ca25c29d1eca4d1dd9cc6f25e7ebfdb9276f809182d9e32191c1195226d9aee85099c3950f872230430d4e68fb37c7f687bc93f3f49fa59d14764c6281df252720d881d8348bd06e4147028a2064a8d76efe4af99ff80c7aab537c92fa8d6fc15000000906faf5e08e75ec248f96062dbdd3ee76df72939db524f749f1cbb378679fc5351a14ed67ee34fa0e812b9a445be1b9fe2d1ec22d96c7192f7b7ebc4da24a5cdea0d8ec9bce3d1334f32c5c4be0d5f426e0f107ba2b782fc31d00fb088b2e769789a0a71875fbb2121e0afc9ee5e9bd23f033b6d3c9eb95db6f1d31d6d7adbbd64013ccca94917e1f8b9dfbd5f8c6dfba000000090a672f98839d8583c11642d3e46c1d4d7bbd6a7bc3d47008dea1bd248ede0637a7431f826894228f01a6caa29d057e50cb093c7d9c4dbae78c272eef3271766bd4fdb6cc1cfc95a4ca9041d385eba7c9e05a3580560d97ebedf8a29a23463aec239ef8b1d50b38c11c58c2e682f2da4f6057daddf89055717beb33550f7e6d8e79cff3b42f417c165267c2b9a1b1c5fd2000001bc00000090a8eb5239528ec46d7f2a28c64b5a69110972279d3c9d30b9d03c2002a5d9559f66af22289d2f6e11e30cb201d6488a376806bff549dc4a11c9c62d043aa1ec224ca7eab383b9ac6f9e82c2329db003cc1f2d6d2bb9994f0641cb30ed16c2dabd525db32b09abd8f4083de1cdb348e2730babd94066eaffc297ed79fc3204443300e2ee317e5ce17e9bb114129c00bd9b000000907c746cde356f4ef87755ba97bf772374d85cac217b3f5812af49868b94f0c9949d8106cd78d263227ba9fbf1d275a70e0086f5002facc3e99bdecd73889f8719445931947c5c06d8a30fdd8cdfbe0a7017865a0eea0a5064f666eb4867d0f6c558f05fe93075995807eb53a209efeb0c1d5e00a28c47cde4340f5b4e09050ea7489a12f9d430c9f4c9b109559756893b000000905dece539ee3d230585ff687cf549f1706d878ba0b2287aca19d2d4e52f99c1e0b1562424db2584ccda92d8f49ebb8aa198ca5ac478ed2857b2ddf8631b73f2e8e9cc61f5192af4d44a345a29cde0ce560442af2ee468175f70a91e74d865f1356d6d4ffa75811d9ed39403a7518ff20b0e39f5cf52115f91f67dbbc0344298ca0e3334375230977122dff405401c929600000e00000001bc00000090fda4dc64d0b6e0d596c0e1c36bc561756b6dd289bf0579af6e8fbfcaf729213c89bfb24e8a284cc3229d4218b85a10bccce27bc4049fd9027fc6c8602756c23d11cef7956a73bfcbe2e2a4cfa72bcbbe17cdeca243227b2f0deff86bfa1ca4aceb1ccea4ab0e4f08d1229f1c758fcaf92ea55a2e164b2d11c8dc3101cdd593e5b4715cd75487c1ad39d038266c8de519000000906e204915a953f809208c619fc1dc5d07f68391d2c644c445274bfeaf8518120844184cbeebb9ee01d12d7f473de90e2aeac7e5034ca9793b01600468c9fcf8bddcdada0fca1254f2d0c47a58b9db19481e0733d9ddcc53dddd96e56139b0b63fcc59fede0d51a633f7b1df17683dfb6f0c31ba19e7dc825d5ab9c7fe7ab769bb7f1e5b973df59ad94404ef2c5dedd747000000903736978eb3d21674fb83f7f597cd969162d1d064ec54c2244cf608185ee87820495f2e43c6113c0d9c9a10bce96e657835af4905aad0dfff74a488aef0ff0a0479434e50fb318409e64be3e748bc1bc11058e060573402823b8faa38b96ec1b30f537c724339586d0a7045fe86e80892206bf9daf2c992853378fdba3862d50d48f0f170cb2f1489d6b09daa6b8aefe3000001bc000000905de96e64849f32b7e1a0655c65b813ac4c270958079104f84c24a957a608f3c08f5f326e677e7f285f40a0787a5bee2ea1e88c0e6fd76e7bca354b7df213fb111bcccd60c48c798f2968891f6a3ad01813f088ccf6c56eddacfde77b6451e530744d77cbe54da14951df6992911b6e6b130f9cc4483903a76e16c279954ace154f5cc0c0c1b083102319eeb7820071bc00000090acf03208b38f133df3058dff97964615b0ed53832ea858f5e5232e1513dcf979c06dd23ceabfa09aafd6abbca4630960381b05b5a8bb66b649e1afb75185c2bdeeb2dffe064ed7728e6c7c219ed77d7513a6cd30d7fc644559d5c860e61fc7c42bb73180bda086c33aee054f3c93ccde08ef26ad18c83cc9a6fae255755213e4a786180e56e29f2505f32797958258db000000904e9c8d785ac9fe77eb1fe6ce5f8f4ce1382f6effd90700e5f32a35de5aac4da9ea2aa16bd15ee504f2ca914bb7f4c08973bd85d4d2254c4cf4f3c717842357b4cd46124ac628713a23fac9ac9b18edd90b3a235d422f063f7e8b8babfb9d6f6178acc4f09e5a21b229b139375eb8b57806127d34513d8282846842f5fbd02e5878a1a0733ca2bd69e2139ee3d7fb3c4c000001bc0000009063a0b0c5fa450096456432b9a88c09756b32e6d66bdc098ae31f3007e8da649704db253f6899a5b209c8e982d0c0136af4f7d8d4ee1c374e6e813e596b5e9cd2bd6525b8b11f4ab9568acf4e72386f342675b297d8f17f7f118f8f03150805e9ddecf0ffe4dd101cd1d96a1ffdad2f5b043d066023ff6c921dd03468a129bd1bfdc64d4cb9f3ac02747a7836b36b09440000009070157e3bd5b9a98f8d41843478f532a1494c44ff6ce8f0b0a5f1703fd55d44fdb088483a7dc08744311c54192ffc990490c275f2641511de67b9c16ea36d7e4178d64d83601b0481f4d453a162894ad11766168ec7e71d7ee6a5268be91bf3ba00873dd422471a50f03e5a8d381114c92f623e2d094df2ae2cc06640ce8da1c4d12362aecdd8bca5dbab630e0099203f000000907b335cfa119c9c11bf107f856759421dad14d956ffd502afaf2914326e24890561d25999eed8f6dfdb508be28456bfeaa3f10616ac4e90e412f5fab3098f72846b305c5fa55d029c8b41e0fedb62936324c087dd991ffce649c347760c62f009f9339c6590d5847355e3da7110d7edb2291ceb7e393d4f3aaac2a286c5392c722efb2147627d236cbf21c4f932daea3c000001bc000000905601b76ce867afc42fd76aff20a4a367f71972ae0c3491940cf7d86873fc272034a88f149b777db5314af27d8ee5d2297d0e2ea72da2aca5a4c60b61e86f13cffe79b17b8139b1456cf6ce97cc8d09d91b2140d7c6f8efc6eb6a022d38d4126c53105b374c5323311248e1c2c0382a5822b6a98f0291a2e3951ff424977374bbe3085550f8fdcd2295c73c24a99a412c0000009002ed6660640ed0d909a58b8778502746dd3433dcde601bdfd6ecac685aa7e6beb33fae7171cc058bf35967c23a6eff9e454886cc3371b914150312d07e9e2c537b314fe2601e588a4af7607f204606c9261b99ec663f440bba9d09049f40c9a624727b79a9ab7d1c0fac885169f3a6c0041b5a94405f0628c2b3aa0c00b9c91b0aaeefffd155dc77ef8742b3c734d36f00000090945bd0ebe75662f55a84c9dedfe4a26b6459a34b08088be24bab619bb0a04bd7fa3316acf96ef0d6155cb1d98fb0e60f52837be3e9d3bbe94369dd944936ddeafecd44fcbdc7a5ae171c951713f2fbfc1dfed5df0d5b9b129099ab0ca6f431d41d7795d6f161e505fc826dd4a8159ef10c0c226b5f06667aa95526b1039fd83ce3b7e647dc4f3c9d5abc6b923c56e743000001bc000000903a0b34c6c481b235ee451e0f7f1f79911999599fabd8a34b4434b7589df65bce82b8b86c1caba33b2b6ecaae72951164b922f9fe4e489a619466939ba61da11949ee9a45dda9ecd4115334d41daf3e0429de570c85fcf6fee05e9626190484825553c63977a62d00b6468a3ab51c443b1db617035a62df5ec5bb6cac4e0c72fdad855a6631b6e368a69408668e17ad6f0000009069fe86ca60be66a658d6a037a49626da107195d6b36b9a9980fa36b967cedfa4ee02dc65a7b1d712a23563b7144bf01240dec3a6f8853ad4e3c7659524e197d85269b5d9d400a96052059a7f2fde806305ea5b099a72ce3fb27b21fddb90346726f148415d062b9dfc3a7d1aec8287e8277ca59595ff4ab6a6b1ab2af0a2fed0e2de61441a59dd679fc03883b89f4a1500000090aa8cea3e45cf3c0711c101be517314b836117e8dd7607051ec1cf36ba94d6f2933ee9bd1a1fab9742ae5f42b15243545f84d5c4a74b54f4fdf90d521a3463d0edf38b91e1f10f2f6232e2212bec7e3a82c58b821489e3bd2c3cd6d1f6263d6853bf5e89d641b83d60e15275eededdf052a9fabe78d893923657ebdfe5918e012e098ffab8c3af1efa815e0a50773e113000001bc00000090049f4b0cba79f7601acc1c4d265ea2b4286bc5d5f1edd22cd268504e2646a1baf434908e2367712c330b6eb1d72ae5f9e921a02b16b2346900589d32fccf831508d193c629d2a91a113e2d5b0c1a976d0c4bcea337adaa481e17b7d30765cd4672ecf9975f819d9686f302e5d6e42e2d2b8a97fcfbb5f4c9866b1e6b6baa65fc631ccbfe90f01f1142e27f16c182d9fb000000906dbb145ceef2d3abc5c18f02447d78fff5f8b95a84cba56a122835ef2aaf8b672360e5ad08c1cefc52c96ebc277e60d80acf0932b83559e245d2f800dbeb071c62ee2dfa94bcf43dd38d164f0fc4fa9b08abd032b327e07854a7681869fb3e8f5eaa062b82861c5f7ad02f455075ee8d126002607aee6d9e7c26dcbd63f726f553092f44ec5978ace375118c4bd71a87000000909bd1e495ba27efbb0dc89786d764ce8fa8d69abff1313511506b3cc31b596bd846814730c065b21269f6c3a5faea23dd340cdef94f2e659b21977ca38e22617a21ada655439dc12646f11253db12607328b22728cccfe7f58b741132ce0c8842d74a1b4de1b27a02f2a1893b92ad5b9a08a522e67d426850238e877e5f6ee92ee231fb1c687b5f1f9706995a5a43d712000001bc000000902175ca2ed22b618ea1961c51e9e1c0978c3b18a9f3dfbe63b4fdf377bfb409b99a9a57a82ff8434cb6c1325ad5c882af3fc55d351869c41a3c4cad282fc4f9d024eef715234ca28074e3db62090369060443cee8c1203b828b3cb5642d1f08ec17b1346b8531292b950d36297b14df551432c821e0170ce7bb91fd731c818b83bbbd89f97d8cbee8a3477e8f539bf4900000009024baca26092f2fabba8cc62624ac7b129dad42ba4e4d350f896bd02a761e6955ee20e7a1559429885dbfdede506ab6db4209fb3a7e785b376ef4339ba56fb19681ed91ba0a5076100c3e923a4ccdf442057d8938dc39ad86edba16a8c92e795bedd0eddea505ed39edbabb06d52b04fb00941077b274e57bbca411eb8f5497f129773b7c28925aa6757a8d4dca98dfe200000090f73a55ccbbdb1543e844d2d349f3950d198ebf791f510823917340ffd0a2e7dadab1a9b861edadb82ee0a4cda718da994eb858ffc0125cf2b551bc8378e32987b113a7f925ac9a7bdd5b90d80992f7cf0a36bbacc04df0667d3e335882c026e41fc613598ad9461d246bd4c69a870cba09691cf496cc0d191fb621c6609ae83cccf9f6ab6faf898aa9a512d01d625005000001bc000000902351960c23c07293d145a31c70485daf68c4439aa9feaf0d799276dc46fb3236e3485bb09daa2c5090494a3359604855673a03d144d15162bb30086265c57846fcc18c46871b3ca6691684b7bc8085c614afef122029d596076346461c3a3765fa04584b6bdf6ce996b81bfd0976f1c91f256283d9c1ed4b15c9df61e4212268c05bca43e502fa8aec6bdd5eed11c77400000090b32f278dc3473a370f56d1f98879a6b0e75bd739d0c23b886385c7fd1a88e4181d08f20f8866eb806e8fa3fe765eac600072f69fb39fa86305adbfdc43ace24e80e46d5d2c1671c9100001b72433078904ea8a551742eccf991e090df8675b9a1cfa345c112f1e2300897d356029d527120f15a532bdc32a3afe9cdf9eef1ba2914bfca023e3d3dbcb3f3a219c6d89b1000000902dab863a0bc4634842f475cd3b7a0644ebf79b1f2310296180bdd2756ce558886021398a53a3145a1f80f32242f962bd5c48b930831ced8e0c988ba0e7b30cc99a6ee6562651311212c29be1b0fb55ba2ee19c1bb178d82586084614d58f63114f03cd3d1df75f48fda85fd4b9979bba159f56d8b98994f2f0249c030530b63a5f6471e6489781692156a378df67375e00000e00000001bc00000090cf23733b594311b0fb7d1510c040ee58e9511af919d8fd730649f45f9450f89c630ecd353c67922e446a8da872db3ae4aeb88d9ecde0a8e45428db9ed21192333d87cb4bae5b225c67c24cd46350e40805eaffddc1048f2627a4615193de5d4d8bcaaba4613b8bd47f11d67273db3dd50f3a151422d9302e190c4ae8d95a04e0abf81611e6ad62a955fd2c0b601d768a00000090497191397e3c5e21ad00156414955be89b417cbdee5ac30db6c42cbb06fbb27c635332dc8ef0dd9f5a271aff6908d1edf26764065c0274b9f961c0a23c5c8550af134517b0a165014ec053f6f616973c0ed30a936c5ed46fb097d6c14e95a2b63404a380ca5831f067605de38b4fbfea1e97a0a6daa1d3bf6e12a9fe54e4a8295f117ba1538a82acaf42eeae694cb7c800000090f91123c2f2edd94752b7306f5ff1f09eba96c7d5284fa4cf37aa560cbd5433d6cccd9a71ba41ab7f0439091f2371f415ac7aa0e56e86156aa350397625302eaab078bec7fb4c27ed16ae5e02641848722aabaf4dccfdb310ed28bcde45d49c699c7a1767308a3e1133602a7edafa8bcb25dd02724fd6a38ff82f3287fd80bf14532931d60a3b05f5550e3f22f849dbb7000001bc00000090d8a8ce8e103a3cbec8be409d7a2f8eff0c5eecc9de737085cda737b800241f969292c83263f294e1fb69644661008c7a45db4086f3fa760b46f5bcaa6cb5e8fc7fd531bc2b22d5c6ae1083e09c4d3a580c1cfedef1b2dc06022dde93f50cc1880368234de8e9f8b44d2fe634d3bfa3c1116b308ff35d86261c91831b6fe62448b76961624b68d7dcf4629ea4e228b87100000090bd519e24a3306dc61ae3017318412632a08d7fdbf477cf37fc9deceb830d2dd87b196ec067eecfb75356ea84d98a6be675d7e4cacda56adb58e6bf5425e82a051ab7ad575ba9a0fffb879d40c2c3f1d62d42818e8fa45d9fee4895227ababb4c2ae08dedbd7868e7d90a5e7f88417def12e3f887a370613654f21c9978e83323aa79e57578de0689da63741c579b72390000009063bf34a659b1a96f3775f4998ce3ae39a5bc290527a765f0471e678f34a465e23a5e88d58e1f1a161bfb67d68ade836ab1f34527a21a1ea93450732f596c17dc14febfa3586924467b4cf7174f307b5a1ebe9061b249f25f39b5536b058281a8c5bd4e9264126a7683d2fbd780696f4c06218715544a9af9f379ef6ca8421d4f5a5cfbffb0f3eb79b995c27ef51bd624000001bc00000090780f3928eb91576884a39487ac01127eb7b9a5e50d96718ea43f4b2a249f4fb35ad9a49c66e568e1be6132af9fb7558be5839cae5fb673912cef2565f1651db4b7b9d281094e1753d3786f8e67db998b0125b4384dd800e4955bd435aa8e3081f49223a676b9f89ea0832a4b3910e5fb2c5617a8139170aaf93612dbcf89eef7f7d974e284d1cd10ed050bb88976823e000000905fb651abdc42bcd38b0425eac4236571f8308230768c99f66a7e820bae332960b57fd93ab27f45c90d4ea9b13e401e65d8d95af45a37271d89008c846e448f3e20f1e5a0a2983f8ebd5c33871ba5d3aa1040a0ba78fd45dd8e46bcf338f5f05f72fffc3ce7b01c6779534c43fc1f36a8197b9bba4ffd3368a0e7390f3051d240bbd61c941b5321c2d3b0354f7fe734aa000000901b1c32814dbe2d228f61bbc89f48b4690e52936dd160e9e591da05778a86c91bbaafbcf70969cbe1aa550f8bcd152aab6e4c2c233481ae1405112353836a292551f84cd3d66a319a4721b7f9cef06f652f5dccc8783a4b06cd4dd62c669039ff0720bb68624fe43b0846fc0d5459b39f0bf0bc56467d646930f77e2f1f2795b343ba6af1f0785518f3b90b7a95672a1e000001bc000000904354b89e98166a672973c9e1a9f2174e1e75475677454ccae4bfa2bb93216ac0946deea01b0bc48c4251f59103205ff4acf6546d10167982d3d0dc4ed129f3609e213f4d01e9d781392b4500f9e3acfa268037e37fe05a73c349cecf8a0d06d658efc9f69d112ea7f81f6d02e2ee79812c293fa8f1f938ef51095033c04d6bd58753d2764f99e5e546bda68a93f44a1d0000009037fddf7426233fa502aa26a100ca32afddf56ea1bcea6a8ccae113020464e9eaf3ce79acaf7853be808a3683e4405594dad2d5bd5efa4dd38e3d56c6f22385821d6f0632d6f22ea3d68f3799a5c9a7a416ad5555a919b22493b82c50b4a7a254e8bea1a13d31a45ac6e97fce4a4029940d1eda7b3055919bf81a6dc213f9c0997a19d927278847552ec9a959f14e024d0000009080ff9e8746dd60d62246370aa0e9327de91d20ff9fd096deb5f4a129d8fa0301f1940aa820060493df3a283a24373bfd15c3482a1e81d1ce1e6930e4b91726f51ca45430148e567af58ecebb4111231f19fe5068a9edf3135d7170acbcec453eacf7c2cfec0b2e94e2b214cb6e34544f0ae77a3f0d59876c2b26f598c66a451d2d4ed519249b13eeefb9ba5570f825fd000001bc0000009001b7e1aa3ba7976e59b12d9b7902b4928538261b7abec7ddd5d558d42c5b74bcf79a072ac57f6db460154e1d707267f9a8dc4103897397cff4b7d0f3ff35bc88eb29c08928b04c271e9fdd1bf932312828106b80554f4289bec063457689bf7e3b1a77bbef582cde33b6a7f955dd099024ebe44fad48d7b021f5aaec6de7ed6f7b8e6e885dabafa223835cd777f63ee100000090e23820c125fb2501cacb093ed8a5bff13cb9d98bdf2f7b6ddf8e2afad290117d7921e13cbc6693499955d409705dcca6936f3a96ef0505c62a718a4c7719b3f3a39673eea8bb1c5664aa52576894be831373e2a66ce4baeeb9b3cb8131feaa2a09194edc559f533c7c3051bc6222b4801bf108328a0131fc298e4e3270d1069c06324f0f9e10c63de5bd1fda1d3227f20000009048094cc88d1afdc7b65205d3697919aaa24b0645dea087ccbd05eb9b3ebf257498a7794c41577a9fc07f57aa77a77825b2f7d4520d62c878ceb9155466da4fb18d060c6b4920189fa478f01a8b1e237b023e2d6acf12f10434dd575e7c3c21a9333bf9cb5d5a83456192ee04aecf76000c3de905b4bbafc7bd6c50f15d326d790d9c2e207ce65fe7ffe767823b465abf000001bc000000902bb23678edd9d4222a245df15caee14d10bc20562720077bc5de181a935fb660863fd8dabea49e5f6b63f2221b3a32ee59c021e833ea198eb5a5962dba1d27b6c0417c818f88eef52c829e73b4c5a0d80965b23e7ceaf017ebb7418d3811a2010e3fdddbbc9e977e48fb147499285a392dc9b9c8580a56e40d389515dc13e7c2cf0f8048952e6f7f8ba8de11d559c4e800000090c40ab75960097cb08ccb5779704e3573153884670882c51d1b79496594c1cb9cca2c2a5d135c5368153698975f36986fceef09495d6471d07017b094c04e4d72a3ac5eec66dc3032da9c78a9c1e506a51b4325d42043015f2353cca71a6ef66ec3b6ff3e37f5b3329eb3527b62ef09550f24f3255a7008cb2681c8e0cb7f818a2ca0d2027adf84a0bd01913e91dc53e200000090a2720b7d1ee63cf4eb07f7a08e2ba88ea387309e3701dc707d56cf5249549baa94e4bdf73977e9d64b8c7fd1d27c951b3838fd87cadf51745187c7415fe8b296bd370770aa9d1ebe037a7669da423a5b0ca3b5a6c12c4290b771b7ecbc326bc3b735b37537f18cb0f1ad2ea39c68aa59124a830cc57a47f7c4a532e78f0e001686b7de77c8141bfa8ab4aec7e4be4966000001bc00000090ebcad0f042f83e0dc516188d56375e13892cbed46f2b29e84cbab6b2976f4e0b78bc264d8f911e8b2fb0d81ae8e81e27e409ef7f2083a52e010f97e100b7b9b47f2da91adab7d7a2fb9f0c115c8bc9ef2b064269ff069596f9cf866ea103bd7cf3401f17b0fc080b6e7bf4c139845d5d1aea1f2084b9273129f858e6d5c237c5f1047debc1d8124473ad1bcef91bb7c0000000903f4fd6837962bb7903227a3816bb451e47bddfc4e75af2dc53794a977bec09c4f0116123f95f5c1fa8a52868c3883e49d32d33ed6ada3188c05d60dd477591adc30eeeb3e3d4046e34c3726f84a5debd1eedb05ba828d3ffc0ca600d36277e37297f1aee35783fa8597d520ff8a8a07b28e4b71f5332a0b29d175c7fc8e2c065466986ba003817dc70d7502849af39cc000000909fb68cc6aff43c30e612f5d4a41071144dd084034b13adbf2f5ecb525cd3289f9afc2b0117e21aece170160719ed9c0fd90fe4af18da222a0620acdaa9d678a9f704c90b4e6ecaae41b91f53524baf8a06fc5136ba8f1c765fcb619e4e43219a19f6fd099ad0c79fcbe750ab3e5cb8aa1495de8ec2cea9c95f3050b744ba67b8e0fe5d56c99c5e794032cf2824fed2f4000001bc000000901f37f51013d4801aa3bc160bcc2fa954d8c7549e73abf48a1150ae118a4064b8f135b5e8913d886829c75795320fa933a1b9a69def1e8bf17cfd95aabc745b6354a31dc9ec7c93faa5207581f95f30bd280e8c3940a3732784194f9ad58c59111c6cd662067c182115a3b76f2a6a82a2071dd1465bbd3e5ad9942dd1e35c8a8b3121e59d1b9724bf06abad9fe21f6f3a0000009078f20442a01962fb1bb0fefec86e16ea53012b034f61aaefe67eb1e9b69fd8a12a5512d8515c507b0199917b004d9f47be78ffcec043d40e5b89e1769556424a3c457b1edb91ae8be422ccaa3778b9d008d385868479cf04df13bd5eeb68d0ad4714422e38dadb97e23496dc820a750c0dcec02e7510031622643c281781b27ffcb69e11cf5f3e95e29d5836aa4d2aba000000902962f159d8ebd65c1e872929b55cafe5cd26114306a7e9046de3757c52efead7f00a5d22bcb05b4c24950f67ebfba24ca406d075dae7a5ed52007bd55634603edd592aa6b0eef78b45f785eac4421cd410927d0226bc01feea663989b522dd6fbfcb2d9101f9fcf48482238d4583c3140ed0b400cef40e061a60c6e7899e8c2b22cb1b3e8a8d5bc2cb4c1f136a61fecb000033a000000ce400000128000000908ae6017b6d135b5e2bde681fe460cf38d338763c948468e36131143628eb17bd88f5561fd3d404d26805f11e389a91ac938dfafce30ddb415047aa6ffe57b50e8887855f2f3b62feed0a2f174a7f1a602d85712c97795c550c409fe7cf49a45eb168053001230ccbd38b86c6612382da100e6ef7bdcd0fe44a56c53f99204741e660e7cd5ecd3f0af35c439c239309c300000090cff1d3d4bd02b23369bfbd7bdfec831b966f01550593013158b4eb7cf3cb1e9dfccf1190d7e365aaee3d2e2ef911258440cb990b5e87d6cdf6cbab3fb49c7d92bbbcdaee23a60e721ef32855791464e7013952f034a0b990add27b4ea53fd7d211977c8ee25ab350c38e22d97bd5f6a0104f53e2ed909ed855987e6e3521308af5f8ba90552096cd23e7d834ca02743a00000128000000904abf03633540c5151c9b161d29cd461e37930e89e8b1a6235cbfa8082313e6cf0bec8a18ea55d0931ce4f40dfc4c86741f7faf853e2d406863db88c2a5b7aa8b22d9e371f7c34878d1494e992af4446515b4021b9a75747c69b4bf727cb70d9e0d61693c8412b8b9f05b5419125f3fcf2b39080ce0fea80062e0c91831a5cdb73cf6b029ec73d93bd2027b873a91c36300000090d93b5935d6f68c6b7fb8ba0f678877fadb3b776373756a4b336a30e2b4db912e66ec20fb8099be94c180c9cb7a8b159e0f4b834e490b8666024aea7d34a303cf3166ccc7f9fb18f1fe9007ba12aeb30f035053dca8e30ca2acdfc211a5814d71ee529ec598466948813ac8082766263b1adf7f00f8c87e1c52b5f98cb2a7452c11f68946542ff0ffd0bc8cbff178653a000001280000009040e994c4f02bd7503132aead9e790f392d492fb3656c3f1c8a7266b3c77a780b93b4e3f2dcb0f15187f6edbbb60c51a19d542f4466d55fdd0b1ca92a88877cd90bdd38bb8ec423eacacd9d9dff2d2db61cb9be0e49b4fb065f88226df5d3210fc15ff5841078a9d6bf54e998307f52d316daa357312e7c8f41b4bb34cab4927eaf1cf6d9769be9ab76061ebbdc874c8900000090f2beaadfd2dab425679ad37d2ec8e098ea35e75222c547880a5554264ae9c6528913ef1f8d9453a4bf6f8a427b466311666cf3d051a4c418db85d3f0016fb1bb3885a4268d08d3af637c6b2a453aa39b22d2052f5f8493ee8024f8319b6c933e913fe391f25d9ad854ce64f639da706228b24504b08fa6226d2f8b16678f42835b9d496c5a8e2a618ebf20b98539c72f0000012800000090f7b055156c514d6c5f6a7d1f0f61dfc61bae60eedfb37ed736d6380bb9be337fd0b997a5724a99bce193e031111260226122992d9aac79696fd6a787876828bab161d96f0234bfed937f8aac2305cacc19433dfa7ea05947e270fdad0ce11189d1c44d7ee339130dffd187013c54c79020c89b20f87b1fbcbefa3ce1f5d99ccf2bb4cb44bae553b8ff0daedd0ab76f0500000090a74e97241f237de7506d4ac93f411d1bc544eb32a1d6935e0175e914f2383e72544485a255aebef3db47dbb7b1076291518bd856f7d7a1ee68847ef30d31c9a27948c2e143d1e64f274496654c1884b514f29a7553011f3d6e95598e7015a54a93e106bd766172c08fd916136c06d2f5144076559f9666dee850bb36b7a424ee0980f36de91bfa2e7d5333e31c5f099a00000128000000903153123282ac8af9c6440ec0cb64e1bd220cb72f4ada818c8912aa13406faddd2ac38e52605fc44aac6c152ec898d52517833d88d2276b3c873a7e62ee8280381f6930910b2fa868d77df1c88400c25c083a63a6da52f641bbd86473973dfaf0aa2f7d678673801da6c2f82a6b65e5c510f7e9c4a5923decf92bfc171d9c22dcfb41ba51c11d769fd05b72c819cdbe6c0000009067fe60ae36b27f6d316dca03c8ef767c527ee7c733b6d92e75e2594d1675d8fecb9d3c2e26903b0866d0acf80fd954de60161f44370714d6ff8ee57862d8ffd7e6efca4bc4be122048a2f7992a9d3b872cae39d2142370680554c73c05a5fb9c5347d1045fc4d9e5d256e287e6ad5a2d20547506d0f3702b2e3f9658a43b57944205fda1b8f777615ab43e92b91ed306000001280000009079e608f27ffaf88bc8cb6acc8ee4fe31a6e8b6d75c22a2c501b78400674f13ee819e727f60d68566660af82a43fefd4d171c8c26225da7554b88464646ce9a4d9f6e873c460a74c51f999f8a9f035b8b0b72a58b3a334a721b176743dd28cb35d97904b3cb2c274815dc267b082870eb165bb0aedf931d64accb50fde038efc974269e3a5c910afff8b54f8885248e7a000000903a000ec1345cd36d5bc9a2c8ab88f1b326d071487a82c070d4d785657a64bb23d9d162482d12cd2a925b7b4764b9c0d3bb257b49f0c8b2b4f5a8d798b02999951146aeda08214a90431ab316d6184f350fd1a34f0a7fd348c25730e7cbedad352a8ba10ed2b2cdd6104838d2543f47cf0a325b908749ffdaf2fa0eb9e87aaa64e13543953e73cd5b71fd3b09a90711730000012800000090a46deeb41e86c9f8cd8ebd074927cc62c69414ac134e4083d9d8357d1a9e39a036e407c9b81f186f982c5ef326ba4691f4fa324cdc376ef5fc7b04364c972a0836e8136d2c37c06da9d76d04e5190189014d75045e18ef66e7ff0f8af8e2675e96502639bfa24c75fa94d7f714db293209b025b56d954c2a52bc065bc74d8d75cdaf200e0303fcaf3778265aa71915ae00000090df8116b5f4dace89bf91c98ae48eb03e5f0cb028f1a417ebc514493cb2e5bcff982e7fd0b03bd8be41dc0c91e1e57db9b3f18ec0bf9a78c90af6e596f43330081b4736536817ffbf70143985d68456d8122eb95d44ec4858eb15e4192da039fe2502ddecc07cdfc91b32673888de127827d3ff19853def30c3bf421bdbd6a17454599a157af2b2f3f34df7819ec9834a00000128000000907cf3c4a6899d753d9958979b4aaf368cb6897220ebb062c96386f6c4557999dd69f3f1fcd10627b0a54aa74effc162a5bd45b11a27215313464ddc3148c1a96c7373f9a1bb4bd2c12ca801e4f752872a14e6125cccc7a50d133d3e3a9e5443f0ba73df26a9c48b477b09eb1610d32c6b2d0c491445fca3be631a159d0f53f6cfd954627e22570be5162d5a3bd14bccf000000090dc7f740b81ca06722aee446f67390d24c1edb81a0dbf5df9e949b68c36954c22a2b7134c417951c573fdaae50258ef58df760d98ca7c370d6e055d94b16a05f4619d99822bf11812bb65a864f2966cf60ca4a6d7cda595984e673f48ecb7155703ee50bb14e70ac2e2372408f57af1a727cdab69ff26434d43304ade33359ed9dab795edb21a926e232489daf874226b0000012800000090939874131cd59c8d928a2b4c130b77386ba48f81b56c36ee5bb1f8c9b8367026e9761b2191423d8607385ddfeef3a1dc7470cea6e8b64307a157eb9c13565bc848f89360a9ed6fe353620a00452f4708233836128baab151af93ed6d55f771a63bbd9a9cfc6ab7d7471ba2af808bc7441a8d269f9db071b72abb1545a0642a1080668074712c65993048af8f8b471baa00000090ec45a5f4e061d776aa01322dc90bbb23808ab4985ee065faf4b6b696f0793fea94c6668070d34d1548c418119b345599aa566c9f37747e9ed7ba4ce07f35e43b313be77232157805e9b2f4ea440d1482072f15721b4f084cac7438e93e728565fa7777fda42f05e57fc749195c1268562f6cc8f844b6684321bf17a5e80e6271dc1689c1e3886174b4b977c957f44f4e0000012800000090c6a0d985a24eb505a74590b75c2019dca9d4ffb6a073985fb16fe9823d05e3902f01312c869e3cde393cd050281dc7710bde0f3e192ea24d547be832a4568f9281b650c3550fb3d19fad36c7a9a4bcd82a85884e8d960fbc5c0ae20000dd9053cf73bd2def3b1141ddb0749c978119301b5076a60300d5b3ff956d4b9d3b70aaa28ca472dce4f7b40d407afc71a0b13c000000907a136f6fb0e760f9561f71b128178372ec592003725326680648623e016679c1c0626e0d87ae913d0027e01e0d6726fef5d7913d053c3b87f446a06df9c975c775152da4e29710dc38ea2d7735571f9a2b436dc3e79c310a691c56371d592f587c5ef62da4374b7dd643e6c01aded1811f17ef0dc310ce3e71e1330acc3823ae356c9704001cef29fade7a91be6a720d00000128000000907a71b069f15c247d5a22ee60978754b545f62d2cc8481c1e2cf3bc4a5d2962f5e8dc2f3221febab5c60e53497abb7befbafd6bca0e7e1638939646a708705be44e0a2043c09fbcae68140cd00941a4c7044810510cd20b07846ed316b9e013e2389010a6f5bd9849b094e59def62de210b83550683c0a92e6143b3b2220a76e70bde3ed85c85d1feadf2adf68e5789da00000090b8406e1cee5df6b62376c4d28a408a46f9aec8350d4eb67b233bdcf9546d297e46a388b5b70925eea5a3c9b5d1cd5b1ff708d04181bb3af657516df0f26a1cc20c5467480c5d6109c79fea2bfc88ac8f1afeff91b00965ab77390ac804c967cdbdc934f7bf7e95b24c3d68b36c2de5ca05b74ee7cc0432ac5cf073db729d830d01e1e6ea208129e8de615a7d978166dd00000ce40000012800000090e63cb00790f7bb0ac6223cc6b46242a3325e24a086634ecdce5a46f67348eda3eba18ba74ae7248327938f17c8b732cedb865ace049cf1af4f7668bd1d8959aed3af34ea6323d60e91cc7a0989b4963601ab527cd86268353780360d40a3721afb9c00aa7a70f0076114b9ba6b72bda815c72956254012d4e68640e2ffb3f04b8cb2c1611d25fdb3f7d70847c00c2c3200000090464f36880bb8d12fe68714899ef3c585ca5ad2bdb2e5a35a1474e4a89fac77f116261c866d58283411c8825642c34156a87bc8a246188f219d98cb39badd958100b1fff0f90612c0fbe67f66e0a7f70f27d554db07dace5dfb437f5a5585fe8a97230750924fdfcb39792c1e03db296f07aab14562867d83c11e8e25276cb4ed6dafae917f382f8de96771aaaf8dc67f0000012800000090df28470aa7412fb9a4732e68f4548c573fab9937050d96182b96dbce36226d3d75297de119870fad24a200c047e3939124690679792955ef63c7e0d9631c004577477da543f9c278176b61fa33c594f80cd4544d7fc0bed15049aa09ff42ae3f3a531c6f029fc1921b5e196865e2b8c819cf47a3efb7bfa96485497f0340cde1a808f87dd998b881d58a722c143d17ed00000090a5f11742f218299dd7c54f36ffb8a3423a944d8f5b12b197d4612b2cb291f5f865e2da3b360dfa96c94c23e58c2cee7d571e530b300b770e5b1718c9f89f06e5cec49d6aefb142098bc3f8e5c45f2b612a4e144f01a387260ad235cb38dc41ad1b9c810ed909f090c301752174caf38d10c00be8dcb99085bb2972b8582a631d50296012d65f8dd0263dd21c18fb259d000001280000009029e111fffdc5873236f240dc4dd12fe70b61dd6134b839f0e0f70fdb5e7c8873d0ffec07de432fb8e21e5de1b0dd17663e24c28218ae0debab51172ecc67469025447b71294caf1b6f3807c9a307c789079df47927722d506c8971c7284f4063c04d050062aaa0794f2b9172907ff7141b53b427c4ac089b2e596be4dfe43e9b94a4159525c71a9fce779e90848a09a900000090d8204fabf43bae41531cf809a3b47351edbe61a93ffb49b4caf2c838c388ca35a5325a02499dbb56464766c2ba0203297aadc9bc523575ec6859de36ce0ce3072c4044e3a9a0758122c5a730dfd8d20904e473bb9dad8b200705dca6fbe3d04015b0bb3e95f483c43c8f9cee6b27d8980cb74b8affe2c8c2690d018674490987d8012128761f6062548e307be10d874f000001280000009079c60376794356cd199678900fda2286c904eb74172b258ea95408af9736a4493a51b78dbb36c3069605d0e41ff37ea4f4b9bb596a7ec52c50f21d5193018b9859f26743dff10d084aa1498722e6d03e2a0300c79d3f77361f9ffa5d036b1f1fadd3b10c5aac4cbbe2a777275b0cee9019b10346c01f60b1979b2820393084a0d2940ccc6176f4b17f9244102af19a9600000090bada804fd1e008be6d2ce121aaedc0501fcd15e97fd4bdefdc6bb089f1236b196fe5a8c7afa542706833da904453e5fc3231fd866b5097fed82f95342f388889c9984d48dd7a7b3bfda42d6c7a5630720bc2ab5cedc1a625957844226af8f58d3caf98a2f824d99bd035096cbfd5750910127403a5a7c77f9a99db87fa6bd5e2738023c9aa4857aab3d61bf83ea999990000012800000090dc4da534ef290868f7fb0eedaa23c0a8c4165ab70b8967b6349942c6bd6eb1eb018ac228b5d166bd6e10a9a5f5f84144a263e7c2d846b52284f905dec6097ca024c9964dc16e7cce6f1f69ca59c1cae01a327bd266ff0713e96d53b977d7472833636963c96b05db068c18801d3fc0cc29e0c73e09aacd9739e3479dc5a58509ee8e6ba96e1c84e3788f75c00b0bcce300000090a9ccaefd804c0865c0da1251985361cd79c6cfa6d8bedf8417db6b728c47b2d6f39b52319562c61f4e0fd612b2cc6abee8acb18aaa0e98cd7ba725a9518ee0c17f5111536c8ffd61667377177b0c0c12279c45cbb4a8e26a0caf8f2417568a1247fd0b57cbb8c0d027035627b765fc1e2e8822cef8a67af8c542d33cc08189153c7eda896562ade6bcf67cd951208b4900000128000000906c15aa33a9518988439f06f604f18eee64cf288665607630443e88ea2b2f1ee4091f57b32c9dda08c2059055fc3917df42e4171973c3827ee8741f046c26d9987f25dcb19dc717ed7a136c514523dcf6132aee4eb6ddf4388ecf9d97f5865fd900559060eb0f30ff27d1eac5012796f621fba417bd9f039e7fe6e0b534c6672f50a431b001ca6b3a8dd98ebf7d9751ef000000900bd97b1b638357111cc3a6baa0fcbdfbdc9574f90848c7a0f725dbceb28402e72a0476cc165a93109c3ad17c4eecce25d00a5dce03489f5da3e07049bc3bb320589a79f8515e62fdcb54c29887206d3c14eea28d267fdae7bbb21bf4361694e44f62bde9d7064b9003a6b162bb32b51e2d3a9d68198afd3c397aae2008a9e8d5547b5886bb25cf5ce2a9efd6b41fb18a000001280000009005cd7ea5043430547b36ca913148eea68bbd30c9aeb982dd153e270b09c187ad31d1da4b518331d6f2d5285612e8ec7e3fbc38847704b72ec1b7d9361e130db6d5a124476285b06e0b53d72d416fcf8000f6b720970a7d3eb475120cfa6ffad9241c2460dcf69d8f6901df0d8a0ed7f525e80c451f61b0723c2950bbe0460b0d7e9cfeac0a14af247f6b2aa6b2b0f202000000904a91b2c4556b0c2c18bd1b82fc9a10d578b258cc76fba5f0405917f24dd0b59c84815154e555d3231620c53e45de4e897d116ccce16fe8b5a288b084dfdf76b687f469ad20ec5a8b8f3c6bd13eb05e4220c03ae33ad4d580cef8d6889acd936d5d68237b909ac66343694015ede09e970ad5dc9545b6e6811c294a27c4982e68e00beddb33a9f8d9e54288040babde80000001280000009074353feff15d4a96331e8c96e0f194cb8f4228dae705226ea556543fb4f9ad281a184d217c87e33b8c0acd3f33bab6dfadd648d4a118758236694ee63235d0cb6d39071523e3f9ed56e2d22c0acb40bb1e6292d13943ac87d931ec05e1572c5c00292e6a2d5d8b43d15d14e90327b5a32e6b2bf4aeaecd105a1937b80cd7d9d26ce7c87c038b008bd429734617626d7e0000009033d883cb15f66cf10636597f6b4d260087899c9af11187c2bd21bd6c691784e413466ca36930d9097d86aacadff1a92e56986995c57dabc03071d32e8d5899291c26aae86e894cd18cf621470e9fd1ed0cf04e280a249991053be777d2c3153785e389ae7744d1b0fe8488ed808777ab2551605b8380b00bbe78342c8ec00ab89ad319ef93a54d4fe933e7af4dedfc620000012800000090343edae0218c915bd4668d00d36b433fe9d25cacf00fa1671041ff09b7a0f0e1e8b401354468d4e16b2b091d36dcb011d1acfd59006f02519c9f4e7de62ae9e9bcd112a80f3dcfe61d507e3956a2b9ed0332303d43fa48525303cf1d388c19c135bbf93035b4cfa7b17fcad6ea2df43b0ba5a659441751bb9b9b0029099978b17de2cd06bccc4fba6d2310ef92c08cd8000000901f1506aec58b01792799e7951fb8e9f5635f6c526e093e6807a3a92179d33aedb6ecb1e42b9486270ea936bbb7e7a1ae0a8535ada379396b8c17f7abd28ee1b3171092cad4c6a85069413e5b1b5b72d10c3c8948274030268e2357983b0810104c62b5a5adae89aee22e2d1f8feea50b1ee166cbcf183d2822a3f9f047da416ab16be50c95ce134ece2c46c00da2b730000001280000009017743c2d174b1eba395df0f38657bf050b34813cc900df131125d77333a9a05e85b5cbaff8a72af69a9cfd4d8c3dcee6248d2aea6508c15f8b8419360320dda002cee53214089cd89f7fcfbad6b9be2203503a4b7bb6b93cddb63ee2e71b38405cbe0656483974b487aaf761343f1517056455a66c69282f27472dbed1c30eed2e6354891e4c25564a51b6c33989f6bd00000090b25da2bef33a0f7e3d6ff772df7c27aaced22f6e0252d8e904399e9bd63e56d27b455c5f542effed787b7fdf546e9995204e1c8eb3b709143913981352ea023669c8ae52d387e1a94512bc07447b36792031d8a3a0f534ab3959fb02c7ce56a7157481929ba14c12682c5330e38ff36f1ed76ce1904e89574c0a341aaf1a7b7f4a5a604563fe61cd435a8f9766d6503f0000012800000090d15b162ef3d3b13b202f4a64b3644f8d5c712cc3bf4d002f736233406fd8eac53d74e374d841d4eed00807e3cd7e631ccdc92dcb2179af718a2645a7d62ce01fd2d889d1f505ec8b0d2b169909ec01b127eb8ace5612e7e0f980a4d763a252e857c2b1a4f96c93f4d7d5c8faeef1bdf519b9ba5d2a8c0fc679b87626f982fabe8ea0c146e938f414dd56722e9153e00c0000009005944da66e238176b99e2e5d23952859080fe89ddb0449eb5dd4d51e8e6cbf22b62ee34866e6f2470ac70a03d0a51ffd5859915121988468397865e21d38d6b9ffd473f9546c7e3559aa64f6d9e96b31239dfa3dd936a9967338c7a477d01624635b153840753632ea3cf0579efb3ce30fe143472d2ca14222bd63b55b8d1cc6995b5363daf3d4431fb236bb9895b6fa00000ce40000012800000090f2a6dfc6e4b364aaec9478a4716462a97c1d58fe31e8336a834f0fe64d232f14aaf208e2e5e1723f42edc8135b521e1e0a612e5aae1782f14220ea3c236b73f1fa49d70032304025b911d02156fc27020d584943c9d58d532f9d34b28ffee8c3d1b7a4a1345ee66680bfe7d26e7f5480111dbb6366796d3bf4f574dc1222ffa9e1734f88664b401434ca77bb7c4df1930000009065b249696cf1a95aca53977c7ed04aa853daee9a5e8aa75883f0f82307082bdd8293d81b5eaa62f4ce599fed7777521686e465b416de7825c8aaffac8e46805488d06a0c5dff8ae0a7d386468b61d2502187f28a1826b163ab321d96587091fdfa9a375ec3d6ac9a870f44c1123002ff1eac15f7966cf5a22634a252479e17bd9b451c96555f7dfd51c4ab8e659169ac00000128000000902a5bf738e55daf39b770a16c6d410e420638a1b42b01a0d7fc5452363f99b419615572e0fba1ddc6ff3a820aabff93265895a25d6c2c651a10680baa6678ce112834632d02a749a1a31a0429a18fee3a176373cd3aecc314770d6e61ef85864d412ee8fdad48d5642e6473e36170fc8004b30f986709c484aa269a8c4574f0979c1b51bb9fcd86e0341fd3dcaefa732300000090489547a0dc14aad3a0117014e18e7ddeafab6c5514a39d5501006b216d803ca1f5fe0f0f9255243bf9d07ea5579f12087a9039883b502d84d647dce2a34c8c42aef2fc3895c2b8c6c26ca5189a1911f82f225d0f198478fa5fee254293a7a0c5cf1b78755fc9fcb732ca2aa9ed59938d15668a9ea2d14a5ea91cc1d17faf814152cebeeaa3bc52dac3031939a30828d2000001280000009016f3c4ffee095bca171701f35e4cd7512b3aacd332669aaced1d1f0d8fc14968df9d1b58b1774c140f2f80ad17bb638c1c738b89375b6f8c66ef71c150988f6c301608327f2656f84f0d3b87f01a6ae5067d6eb5e4603a74084e0e208e06ea2272b4382c16eeedab05804824cc916ffb281a8c361e9c19ecb2de3d652a9c8f200930b45c0418817fc724e3009a4dae51000000905a70670a05add78b99578d58e475738e519e8d223d8a7e3bbb3bf58df88360f57f75c73fb678f2f81315221cbbe5ef5ba94e31d230fee618638c367e8ca4338b57294011cf6c76684a1731320d11835b163e3d5f651a88b228e2265109c4fdbd352d949d36a0257875aa87a2072d143412a1194f09f2b4ea6ec475b4f44d1a95bb8f9404472b0ce951c86d4c4fa9ca2800000128000000905a25e0b4074a254a00e9e4b4311539e9c87a0605bb890d4d8528d6f0e32276814a8708dec671d5c385d3e05739c7a29a348ab687749207989a162c259e1016c9fd425c7f0273600161b856556f572d0713fc866135fbd3eac6db7e27c2269704e627d2046429faab80ecfa403feee3060e8d0aa54cd8cd0e4a96cdcaceeb8a064a3f5a54b0cab4cc76536569148ac897000000908a6df6c2d63108c69d3cb1d8468ae7b0fdacba6e3b64ece05d2d83b0248481311b5f646e249da6261db2aff92057fa8d1c88321ede1846146ac212e2854d71bc90977f118074069f68274a6077d9e37a14a4f80356db5183e3e2462cdcf44408d0b4f8583017fb14a3312abacb8220361f729d781e2d0c7bb068d5c212e27d6a499464462ec88b2cf9faf5dd4fc82bb900000128000000907ab775b93d3bcff1197e4efe160395070c3f2d34377102df3ca40479df0cef553f6b613e86bae2340b9a2ba947c8c8d6fbb7d8da8fcf5651e1ea47979d636824cfe694cf1c733cd4dad9b33e5b03384b1669bb05debfc206e18ad93d3e5aca0cd355a9a9e66f5cedca0c0d7803602252197b4b9a326307d2ef93cf1c52e583c5f15e753894843ee195d978aacc9b606100000090639a3d2ce92d0d2ca07b5841bb24863dbcb295e1b37405749d36750fee245ac837799ccf18ffee3db14ad1f78470b95fb29c319609aeaa84dc3809409354db3cde412909a43aac5726e4b1ceb51ed5942b0ec926610ba9ed133e225be515ebd3cda3d32bc70751eb61afef2b097184b806a0d9200209098133ef1ba0dfdaeb2c8f894fb88fc70b8a43bb4118bcb9e6a7000001280000009028a49c8bf8e6497d61c3422fffe9ba04d4fe63243bc849809d4d6f8ccda3ca9b2461af482ef2cee990f1511ca77cd70ae319b81cf1905a4fdb7bd487fc0ddd197280e0db68a6f2c6aad4a7fec335ed8c29f1983624db051ff084b816791a9369cf8aa9a4ce6122fc50bbeba64ee495b604afc85877102c73ddc28539468221851ab8f4464aa71f5714ea130306a06087000000908e573f4ff049b51ebc4a82e8496fc3542c9614346d45297d49547745ab63d7ce1823b578a61a83db6118c44b7389e480d8fcd3fb6d3701d4d3e5ec79916a67a5df4c596622a069ec79bde38af4934243139196142d8949ea0b19dc71b47edb3b746d136a5de3d75f5f3095063cd082bf2d99d0d5bcace6c0608cc59b518af71491531e1e92c07fcee7cacc06622e1aa80000012800000090e7f111807a317b47e4ae5d92b7b83ca055556314533e6726b7bee354ac3f706bc398bd861948672fa5c744f6d71820061af9a59aa05a64298db4b8f6eec92410e30e4cb46eac82e3ee91d3b5cbd6a32f2086a61baaceb641cec33dd41d9300607cf09862aa07c68938ec6cf2da711c7a24cdc553f36cce7153e98ea1faf0c8feb6458fa74c3a8b8015d13f68f1b4faad00000090fa4c282b109c5b736695b80bd15ff3857b21a81af2a6d45891b38e20642cc5fc4809ede28526ae4c3949dd041db04e51421a8a50e292670798be8f70f032208676d95d2d5d0e669da30b90107b9df4db0526884ef9cc64334de1fc32d68edf518032431bc2f7969f3742dcf939b3fab819b84bcbc494c60bd75074a8aa419d0e65757b8a8d3d45385f49dc744f2494900000012800000090575d37cb7e6d54d3e6e7cf56a083e6de489989a9afd062b320cdddc472f2a6dcc5e9452e454ba723ba103e5944a934353586c25d1093dce2ef2be0937dc387d4f3ec68c44f4bb146ed296af45ba722db2d160be754560fb4132cc59cac4bd8f34c8679c5f3a1100f48bc2ee0297913dc25487ec760d1666f60219b5ba2719dd5cc7314572b070d858ca868237d21f9f9000000905c4a242a73c01013b39b88ca6192db016f923ef22e5282142c21af1fc56ed8d3d8712d54dcac484111ffdbd9e80a13945a58a3ebfacf570c9f6e057f1a67b625c59be4868ca88aa0b9ce2c139d52655616d34c0743ba2d82147d6184055794cfacdbee9a616f8def4a12efe41647946d301f1f19b0aef5d53da3bcd03185841abe9fcde5ddfe1acab994e9069f6bf809000001280000009047482e38f4982ab0d639aaafac960ea87c2e4e4e91c6f34fc7370961bd054a01cd05dff22ebe9dd03a3317fe2139ccd3256109b9aef3886b6fcf258081cdb56f939cd5c91f6d5fb000542b97350f78f221d45ede0b9a56d752be8baaf2b780c5624d24e4a2e267f3fac5d516a3edd7c91018464d8b03222ea0c45603dc676a78c43d3c6f1e29be670a4b568c285d306c000000901054da3727ea61edc015f6517c7968f3005a4b993bfeef86bb35173b514f962319e02cd0c52aacf3ba6a25df8c266e397d3895cce1192647e6bd6ce0c2a99af21aac1873cdbca36f086c55b538e092001978f44b9d25c081ca3922daab5f98f863589bc49539e37981932bc311ad3d741e212b54370942d9f8d9cc5e88497f56674b67f13ee02cf0b02835cb35bb550500000128000000901c67aaabf232dd1e5dd4a401774183dbb92643dafe9e37474a5dbf5af565b98dd7f347eadd51272601a5e37ed55a389e0451872169a846c7b05895f7acbeaa4f8dab8ceb4a98cfc6e8c322d9c01dacb30ae4f2d6005bd7bcd31c916ae6133820f42f7a96eccc245b9f619a5845e6bb8c2e7d3d189d1a8498d92f8b24f259f3665419358a3bfd2afb9e8dd65b23c51fd400000090890d1e42f9367eecef0ef460f23f00f26439772ca68ba001fc4920f3c35e497c2df7a35ce968271d92c02ef065a96b118d15338303b72433601f256b41ce6b1bd44c8c5ed65992597cb43b7654e171ed1a7ac89b1703972ff384a87d14852ccd6c4b7109cfb26e53282fc7890096700b01f543f4795fd05ba7209e56523a8075e954d7fce44242a6f80663f07977855400000128000000909e238d2bf97aedbca895f8e81240c4091a4d6c925b6290d90930796c91af130d5831de146886326ed259dba0b6e2a49bf2121770cff1d1eaf879af515b5f6ca747cc3e2501d05c2e3bb1d0c0c3fcb10809cb8fa87f595909b126ce142171e6791c9780216ddac689e093d9633c101f671c7d5f33beae83145222f53f35e7ed9dd1c9156d285c654ae770131c8cf2d43d00000090ac184d834b01604cdca29bc485e689224a23fa6f459ad340958f46050f9a864eb7553b5f79dd419f53033ba701f358b3a130219e259faf446312cbd242452f6f2e97e7a30b3ba0915566b62fbc0b32dc1b0b269426b4f01b641f148c3037f3282bc54ef830e74935aa32913b28d666c827cfdef2cf08479063c64085ec646664da68cc67cdac47d9389a49860856128500000ce40000012800000090dd13dcbaa27f29af8a49ed03d3fb6f25df257375a719f1eebcde8e816b38e8a368413836ecfbaaf9bb1ad37f400483c6faae0efb47112d268a26d2aeba6770cd103f54a9961021140af2580a431542d22dbb9f2d3c66dae6b62f9df4ee66e526e57394b09e2e8d7f847a7891e29d18f32010b1f61f58318492970891419921b4193582b71a3d77100029f1b650109c98000000902417f5f686ca8342a33424af3a725c8ce161f83fedc3115750ab7875ca386d663d35bd14d72a8ad2a43a5522c2ba272766be04e8782d7694d184ca90d203e1dac146e76c2acd95fe7428c47f421358b7263ec0f68ed67066bae896db04a261f51ae21a0a5375636b87f66827bf1ccf8709fa34a22dade740cb181d4d22a3f6268892e166078b8a0c3ab6bef1df85c013000001280000009046a8b99ff4237461e9128065208db69aabf69c6a316c711141eb30a945665e8809e8b636b5f277011aaf797398605c7e73ace050fba93c7dc0579b359bd927e378d393fa452782fe518b91b6f50d8fb21f86424c793876821a281712921ae15016c1585fd44a434781be11bd7d919f38007b6ad4fcf1cf51859de1dfe9cd2b7c536020be37be80c5752f5077a1baa60d000000902825e5c922ce813d4032e9667446af97b746e5a055e9409f99f46235c41917a78b7b5c204208a9da115da0cf4a651903b4a83d5933c85ea481b0233a24d7d9d79af9febb3f55a6ba061bf93b49b6932928c781c98a181875b6dcd542581062af10f1d79ceb1eed834956f18cae39cf292125bddf74820ac00a0561aecedf8a898e4d27113d0839cbefe144740f5d2d230000012800000090bf46322853c0470b44183f55ecc4ccce9bd85a561d0810b530efe91b5b512043e342a47a4467de0eb7d0b8e81e7132ec8c558c468c8a3d194fa27a5819776b617079df4a4180281c2c6ab18abd9f0e6a1b11cd0a5560ef2ebe4c2fba3a1577b5de0db3d65f4b7c87ccb22664e9ff2bbb0f5881b341ecb35a3b744752ef6fbf7be077229b7291f875e44eaf5032133023000000904cf6a0f4062e35092325585b338b98a0a7551bee77dcf40f8b9e2c8482a8c70ff8d9b9a55958c5672ba4b3f8686a0a38f01b473aedb39f79c447c93b997b2662e061f8bbe24639d4c169f001f6e7bd7628787f3bb97fd31145f9e9c21d30708e2c1a4b8de501ead286726b6d732be6a326a5e081dad1abed1f0c59c706cc302c6e12b89c7c9d35ffd2d2ae6a1b1eff7b00000128000000908941692bc4b6f96359dec7e2ce44377d3094af36814d90c4a9eb3f615fed03b9ef3e4307d7b264a88704ca13c8bb3e0322348c01fa04bd737780bbd54867efe72c0720d35e466068fb6e29fb74e1a65b2443c801f4bb8c6bb02eff5dc9c0e5f90719a520675ec3d13ea5667ee743028721f85ca31c75a8c0b76dec09f2dd72b8a48cabdb37568ca269d33da098616c6c00000090985347d0734db684f784bcd328e803e5abf31dcc91511b43d9e91b80af228f7ac5b4aee04f9995de42e6ef0d949b2886232147a9a2853fe53c0d14b364d6fdd343456111339d61d6867f77acddef9e4f2314c29b9ee01e9f9ddb77be80b93e591c55160c367c0f9d55c74f57f12cd686010e05aa6922ea14f8246749cd155b9c93252e0a84d9a0c70380b752422240d100000128000000904e06322cee46fefea1dea5dde5b6178e61c4bbc90a33423552f30d06e6a29a94436fdb1e54ad228513d13fee625cade73ba26d17dbee052a96083ca346c8b1394603e20010dec693da5fd7df5f7adbb40ec6ffc7493396bef2a6a8ed2a58a2e0777552b416ab5eba3978393d0570154b056c0e8a134d75e86bb46310f386ba7227b833f579d5d2a26ef9cb0a3da741db00000090d46206ae13047bea8df14e0501ce058789e5f2ce0b568df31888807d9c9bb44d0f6f5637d6a6b6299d967e662b73868f975b55f25596accd4a04f90204c6deda31ea1b35946e0289b1e4d2d98eb950c207cdfec1705664556ffce8011db272c79ba56c4e90ff9def836a1b7ad0f6c72505bf7c35c3da8bdf2626d94a27d9dab1bbd2fdda8bb15a68da445e527e838e6c0000012800000090be8491f41780d06a961083034c766d60a654bcef483a4f958c63555f80b6ff5dc83eca16285346aef52950307f581ee3405d9e8a82c441f531b9c6bde9d5a8436112622197599eacb7e7dcde53a9d6570244549f32ad30e521ee950fad0c1118bdf309d79db58c36c858a2500c115e0a04f1930f87e3b277280be27e17b78242fab7aa2e5df042fd38f21e3f8f457a3200000090d4218fc5d04903e225b06ca321647866643adda3a5f93c3e593691047ca0a6ba2271cc9cfcf53295ba7b223afe10cfd78a9a3df59203c611747a175a72b050edbfde493e8215103300be21e0a1f998bb116938741b8107a9b7d306ac77c674dbcb2617523f0f93f4332f14f5bbb3ca61282a12b255924c748a9a55632d769009360b61b75a0182e6a0b9284cb8ece84d00000128000000903edb1ef5a79f1e476120d592fc61a99e9c53fe919b0b097d0c0b676f7627fe031c0ace18bc34239c6aafe86b08906ebe8b99f38e5b116091af6320ed1bd0c04c560b340b2eab35a60eba91e54f448507162fcaaa43e1836286a7bfd67b70ac1bde19834d3f42705abb34de8590d7255223e3b3a9de8649712c9045926a6b96059e599c92130fe7172c48da1a8210faa50000009037cd152a57274d6dbae31d63ce20135c9dfe2a041394880643b8692a25bcc60a384cb072fe55bfae112a81a64e9566d6a50fd99490ecd1475a52feef629336780fb3792d932e73898b7c284ffdea0b0018c5779afa4ffb0c7e1e14d81abbc7fafac1d47a6f3fe403fc0ad022ef73920504342354d41109a010310d4657a6ea4047c0e51feb79c3ad7072bfe42253b52d0000012800000090c058cfe0177ccca32a24986e0bee78ba1e4f9a45f11f69fefd8d361eff8073b8914111a7c98e9271ea3957d1618dbb1230e5d7c53687b42f77a00e895e9cef3550f32e31f676a72f5b75e47ad600b7d42e76974a3b5b3d025a401893dacdbfd2109a20d9e5e3c638722770c03a2c1b750ec0c16beccc2a09638d5c8a024599018794ec67d804c3145b7a1a92f38b871600000090efc71b5b771fb6040ec45f8b716139a6b802765b99f8050b7b672e31487fd342b2c0f4e7d3fc2b94e344f089870f6e3e096526a37e1bbc1fce2a70aa3f22e0db7da068c8390a382db7ed5c5e41c7c1ac2a0c9a29b14a35532b89e8eed7ae30fb8c7b18acb8b77faf97a0f8639bb60cf2217fc23e559c83658bd4fe5efefc07313f5195d6ecc30b621e09d0315038ba880000012800000090b293945bd12e8d406ebd163c98f00a562608862afef9c811c2b91c4fea017f46503651eb6001bbd0191474a34a90cca55b0addcaafabf31b8ee5c44c90acd16a9baf9117e3d93b917607c1e26a55783704fd1aeb4348a0ff9ca465343575f256099eb772be3e124968e3cc723dcc58c90ab04676c9f8d64a9caa42c80d3c3d1c3b16a1c95002f38ea74b5e96c911105100000090b1130f2cb52cd99a89131f63af3e1282460d49364e38c27280a858078c2cdad4f4d08ab90e13472566cd6c95f7ea5a82dc14775b56a1608993ce3592f9667a63932d7bd06f411767df405d485c2a2bd3115042e56fec10e71476834f6e9c8886ad33d46cbfb36a5d8c3cc6f0cdbce4dd119ebdfc1d973306b22a3f6a9ac503a84bda7c6713ef6428546ecb615241d205000001280000009052b79f81961041848e37f5e81bc82dea4b231a804e1c4f4e136e95883ce8d120f04a32ac75ba48cc833c8b0b84b8faba75599b791b51ed9dd6e361fefdc326667eddd06382bedb59c3d6a8a1a9c2c1340897f6287acc52f489e18971f91b0bd5871a4888da1c9c2d35726c58dfaf4f3a2d0d2546b1ae741b63b7ae87b9cbdc1582f39bae2775256fda84f27b554336bd00000090027f6391e00821154d54b4cb0fcebb433b9357544c8191fba1cab595c3a44331538b76451430ccedadf9c68d4635ca5d9201f66ab1745c04c3bdf520370d342468c3c1cd715d18acf5af6e338f5b6c200f229d582966fa2dde6e1ec9077b62157a481a3405be207973e3d808f3bd01501953597b74a5f286591ecade14926a4199b00490007ffbb4d0c47c710ecf4baf0000012800000090264704174a964acbf875467752d9b8c3425f7831274dd0e9a52a6f86c0e82bbcad6e0fc871168831b0c321c984657acb70072acbecd04a4a74898a51a68297c557bc2e8aa57c90c631898981eec68bc02c450ca20800d69b151af35af08c5c1bcf65490c65cfde331b11a69be2e8db6012879a7659512a2b1d8d0ae99a907fab8a0d346caf670e2e0d66c7b8c513df610000009001f8c3e62bde000c69f501a59aa84dbce6ddd03929d9d694f4993ecf330b8da68d08494b3eb64e9ff746b5b13d2fe131c073a22a252ad59f71bdead76a17ff1ca77a8130a2946f348f90edd6c025f05c28f24cfc805bd774570ca71733fe4159a55f41c542b64cfa402b7668723ee04328244dbd8f295c588b8b303367f9c2c285204839956439d6f2cb1ffe5a4bd821", + "calldataHash": "0xdbf6d088e40ef7d0e0064c202f4bfcf4556b135b70f9d335cd4d587d79e0aa43", "decodedHeader": { - "bodyHash": "0x0ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf41", + "bodyHash": "0xdbf6d088e40ef7d0e0064c202f4bfcf4556b135b70f9d335cd4d587d79e0aa43", "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, - "version": 1 + "version": 1, + "coinbase": "0xdfbe2253407dbd0a152c036a2ed1237465c243c6", + "feeRecipient": "0x1cc1690e2bfa2c49ad640289205cb9547e1fdffff97848aab22d8a541ec3b9d8" }, "lastArchive": { "nextAvailableLeafIndex": 1, - "root": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02" + "root": "0x1213a7f84b7be98d122a1b7e15013610eacb74b328c20f369588569b1f6272c4" }, "stateReference": { "l1ToL2MessageTree": { @@ -92,8 +94,8 @@ } } }, - "header": "0x1a005071a487e4891787073a91504fe6ea55280bc6f65a021fd6f7ca1f10aa02000000010ef928e73adbc5f53790a7591f274b0f4179a533e21da23f2ed7defe5af7bf410a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f51000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001801a3d3e40c90cd24822b9c268154ef14d4639febdb7af81b554cb2d651b88dfb100000004160ba3a7c15d7dd592a24b3f14bfa76a0b45378877d4dedc5f126f47844b99b2000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000", + "header": "0x1213a7f84b7be98d122a1b7e15013610eacb74b328c20f369588569b1f6272c400000001dbf6d088e40ef7d0e0064c202f4bfcf4556b135b70f9d335cd4d587d79e0aa430a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f51000000100d944282e11bdcfa5e8f2b55fe80db4c586087bfc10e0bbba5724d30b8c15e2e0000010001c16141039343d4d403501e66deecff1b024bd76794820a43dc3424087813a2000001801a3d3e40c90cd24822b9c268154ef14d4639febdb7af81b554cb2d651b88dfb100000004160ba3a7c15d7dd592a24b3f14bfa76a0b45378877d4dedc5f126f47844b99b2000000600000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000dfbe2253407dbd0a152c036a2ed1237465c243c61cc1690e2bfa2c49ad640289205cb9547e1fdffff97848aab22d8a541ec3b9d8", "l1ToL2MessagesHash": "0xb213c9c543fce2a66720d26a913fe0d018f72a47ccfe698baafcf4cced343cfd", - "publicInputsHash": "0x1256090bf682bee2a1b43969d13bd8921ab74904a46a578d20534b57434fd60d" + "publicInputsHash": "0x06ec35c3b5e33ace2404f6995b2bbebc1164ace46a2a36989a5d9897016afb6d" } } \ No newline at end of file diff --git a/l1-contracts/test/fixtures/mixed_block_1.json b/l1-contracts/test/fixtures/mixed_block_1.json index 805a3869c17..6fa74440315 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -52,20 +52,22 @@ ] }, "block": { - "archive": "0x238d559a05a8fef1cbfcc8b7e59836b7f467fa8e93d433bfce8efb75a6444448", - "body": "0x000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f000001000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d90000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f000000000000000000000000000000000000000000000000000000000000071900000008000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004410000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000048100000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c100000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501000000042ea6fe02855d8c72905f35f08604467117c037962e324c9a793505138558b3700c94efd9afe573212f9bf596ca3a4b42ae57f59e670a7cb5b9440c54bd8ea2961856bc4892b0b3f156ed2aa87463c389bfce0fd675a37cec77ae5d753fcf593c12f9d3f397c2edc9e4a6a5e485641163525ca802e3bd93994af997a9b9a44f98000000000000000000000000000000000000000000000000000000000000114041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001180818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000011c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1000000000000000000000000000000000000000000000000000000000000120001010101010101010101010101010101010101010000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd0000381000000e00000001bc00000090c13d9d0180efb0cf4a6d1676f61f735ed5237557862809c657aa892a154646f002740dcac518dd1d753b4e8c83cc4b820d7a92f8d3455ef8d6b782406a966e38abcccfcba2bece327a31225662a0e51617a0f49b0b6dbffcf2dd0fd020106158903111091982c078d4c3674969f364fc0a71e2354ba07e5794615562312bd212033dc0cfd54419fcc5ab8efdee25f19100000090dccd8f5a0daa473e34d076eeae33bcb6afbc88dbe6897c7b315149811fd15efac96150d7e0fa1579376d42f4b911e155eda5ee5456a9d6c0a699643c6beff9cb0eb2e1b36cf3fade1af2b33ee0c0bb472acae19d029a57a53882b8ba8389fe0e30429fdf159c9693fe2006334692e67b1b1fcf6fa166824ec7076564e555e49dd085a8e4b54bb1ac0f18e31118190e6600000090379379b71c561c7622aaf4ff0d200b4aa507de6b631c841e84ec50b80fb6719d5278706bf3400d47296446f1c13e75cabe1732750f02a7ba2e278a6f5b144cd0333519ed882d956d16cc45175bd00a6c16cf2171d48057133603ac31d8bc578b9b481c0a2040a5725d0224e373b3f043247e2bc5856e7216bc45fa196168132578c74e26d88b4ff36eaef01d3c7f915d000001bc0000009089c7007a588bd867a1faee4af2137ccca39e4d930507643479212f21630c943c6f430108f4bb721838c8f1bb34ff73841fa2c37934cc6e2cdbcfda0e9c468ad150dddc942d41b76c0758433eb4a0242e26e30592948a866293bb4e29a584a8907676dd085cb9360afff7ab84ec5801fe07a56a33221144d05716a7f2db7ae035b7e80a56341d289af3914b0721a00d08000000902b13f3df874d19d5829282e4eb39007639ff7c211e86e7f8be619ca4ba39c5d81c8d145a5192f4a3f10895e2797f2e25a7131a1bcc6b1062f6af45c94d85de2c419ff98bf9cc3715c1039b2e8ed4ad6c0499353d1db9426370e35a27689ea1b19ae662edc37422f8cb8592f9c6f8fde61dd54d1fd3bfbaf5023d7bddf2311ca15af50e55673a51a0a914bf4532c9722000000090539a9203f6b58beb64bc593fcd09ed470344d5394aa75974ffbf7f996c7b066a8f2175d3e9f10ba74227458fa6150ea458ef71baf2845c3ce67f771741aceb9abc9ec54a601399e81afd137ad3434457239ebf4d9c8c846abbc844ddbf723d686b365611aa69147196cf8df5c22ea6dc27f19ee20cf6fc0390a49c304a851e624db98d7e5ad0f450c3c8bad71b4a5de9000001bc00000090da222fd69c4e340b559c3dc9bf8d0bf6008a106d09f504acc95a3ab1c93c1481e2e2704e786271b93745fc97c7b0788a6eb74aa6e72c6ad2b6877d7439eb41279bc6107b7794a16257bbb4d0a20ca42303e778f0158c37a7cf4698c7dc402292b6d224b91f884783885a44c4b22cb2e1197b400ffb4fe08750914ae9639d5447c8bc64ffb989e07b8ce53a2043185c94000000908ea72c947ebf55d77062f0b89b668a142a198842dbd2dac59f115887ae962f7c162ecffe95eb0078e9ecc34874060fcf3da11c14e08a92203b8fed924ccbc787482875ff28aaeb45859aa0d1d01db986137c1764dc112f53424f750a28900c8c53e6973557e33d7376e0730bccf2a5d606a3e795498757161646d549a0a5af18e3958557963648083d6e76c9fc6ad1e100000090fdbeac241ed3f7ca3be7180b73150eef39d6a366bb834fa7903267719e26e83579db2cd65cb64ea43a9d203f5c8d837c1efa6325e91e032006a7f5e98dfbd0eece6aa4c7db4415259601ddc5b049736c0bd34df57ddb365dbc441b7905adc29628e5559ad6d5b3bfe0f0392ebf43fe810d8a808231fb44958c9a96fac08161ac0956714bd3c74d9c851197ca7b1a8c57000001bc000000906e199cef996acff8e6408667d2db579909371083a2b40e70dcd78a3b6c655ee906d32a6a2e4bb9d1ca738f6423f006ffa3f7ceafd91e96eea421645efbb0e40388f9687acb66dd29aa5483254c111a831ba7e8598f6360924da54146a7a03d128a412f9e3ffd0397856b66ab9e8b524925cd75b0ae28efbf9c70b3f5b6a97e3f035453116809651ce45021ff596167f200000090dd2cba45eef3205574b614aa62165a4ee28430fff5b14a32cd63328c61f81579edde9efc3dfe5d7dd1526640f56ef9a8413c7c404907d88f32d16dea6f5958a9f56abce2a07c97569f8c26bcc74f2c9d141b0c142f32949e264a3fa9d1e77083e8b916c2df83261c0da074fc461a2bfe2e1c37540455dfd845002c4b409f9226cb252a4f11eb97706bb34fa6679068cd00000090e69c94a722b2f3cdeab1fe8314357bd692975c2261756d4f2e42893ba0bb2bebdb3512194c20a5b67bd891cb60c2d1968dbe96d5484b4964a5929de3c2a5cd0effa311707ae0fba27fc768c80f4bce83231d783024d854556157346463fb7012bda42dfd618b0aca7f58cc31dd15c6972303ff2ed3ae6d388f478577aaecb76fb12e7238ef29c2e5505477eb86b80477000001bc000000900f5ef582e8f2b358a287f69fb361c846bc362796e2766f502d677b6146517246b69ce262540e375c2424a887054b16608904482f40ef323763ed9e7f299404f25d608e6e0e4bcda16a92354986662e882eda68e23fc827ca6597c85e7b2c7f1a5f9409f6c7223104cf3b5dc3bbff99071977631eb91b2113c5fe3e3ff3ddc8da3bb01bc785683396c5470183f910dab300000090c51abbf871caccb44d13c60c2a6f8429140005f820b70f74077aba9c7f32cf74d9ece0ce1b24cc19980d787ba82d3f9186ed2d08888626deeb8ce1f74846c70ec434efc3e33bfbc86213df64cdf73fdc21fb971bde4dce6ce0cf00e204e065c5b1f57cb613c3ed8ab6e54d31c1636baa264dd3ecedfcbbb1dec253095757d12bca1d76d2631ef94e76245798dd47af030000009022d04f9051a6626fdff3d609739cbacd11741343c4d8ea3177ca242e4de50b37ccad4739ec2c882d5d17bd084f1d3fabc72268d28193b522600a4fb708231e58a7ef5b23f91389137beafd14a7d0df55048f605b84bdde04f25c61ba7101bd5c58d397375879af5a4ffe97152630c801260d6e9ce6fdcaee074e2f665238668386b35a772a861eb4e9b3fc3556ca1974000001bc000000907e2e2070eba81d16a60b826b11ad0a7a348148e4da106d6e92e01e2ca53e99cd643c4faadb85efa26d2686e15df7111e080d9b2f08b8d1799dede4f9091005b95dce8018d40aa6bf530206560bfa3b6005a351fd26639df63ee65b51de7b68e077fdc01ea04b73d878c3895dc223130302ce398479d642a13db0eeea714edbf4b6011a4dce09c1fa516a27aad43606e700000090498ba863b488e2698f2b2020eb4c7927ad3dc4c9bf3d7cc556c123db1ef46dea337cd5cb99ad0b8e521103a54ca7444a8230be7749816a240d8b0f88522c629f98bfc97d8e980244e4aca243dc1d8256289d3b37f200f4c5c9f4cd63a3edb7954c75d547577a5d22bf3f77b69953bdd323b82b33481f27c55dfc4f15c859fd27da61d786836685a16122ef59a7ca7ac70000009046c3512b1c79aa1e065a8e4256c595c9293dca1d56fd05a119cafab59416499ad8aacb94f92d99388f774ff6d7d0ba468fdacdb8d8d595c7be3ac58364d84d220bcc50460aaab158b837c1f834af3bd918cdc85c632337166ef39a085b6112604af2ffec61e77e9023863308bd2566751f5437bcf1ea2387b364b9099d087cfc5bd0e26ecacbe348de1b418d55b4875a000001bc000000908adab8f017417b5bd46fa1e9779632be5afba45eee6a58daa7754be749861997acfceb86f08f30b61ff903dd7acb46108739d67425d42f335498d98640fef4cabee4bc1593be601b8f85aabd966b24fe2147a3b6a75dfec1d644e0076f106a4051769f6aa62715d2e62bec25379e3fdf2091a5b55925577c3485574e37696c83a970b96c169e46877baa784d8a7666c6000000909d4bf0f2d2de7b2396dec1959f7b7de8b805425819c8b80798cae313d89e545d8025ff56d9a92845135ac58fe672a0fc92245eed345b5859f67540a5c19c80c499374d282f293a6c6fe12a8831a09f4a1107c3e23b62b0c34d7bc37d1fa74e9a6bf158f1890db25e9e5af558a463c85f104fffd61d3945110ba4543ff2a78e36daa74aea25b0e4905f0b76b8102901b5000000905584f775caac62723960eaffd596a5f64c7083ddaabdaaebfc2e60fe575109bd1e030a83c7d98fefab9494250ea6191e111f06da98f325b6db114b081d8277593d7c7c21b59248510cd872041c66e8480b33673cd6947e1be4673318549d2fe339e55c81b22301fe039ed1f9aa1004d51492f446b0797f7f27076842a05de5d9c53a8f0b45987af90fa814f5014c7ea8000001bc00000090e41c2efc5d16d3c931e59cb67106901c97b62ea2e65a49df476d10bc4193d36deaf6fc746c076bfeed7572d833c13ad4a51c933a86ac96ba919855df3c97b3a970e095a8de48e656eddb0630d208c43a1ef50bdfb97e408c7228fb2a13553807cc7fa20370e6b1818b11d43242ca70fd2686012dddb4a7920ad9752c93b0d8648338b7d453efc270a19cb0de5fffa2ad000000905aae1d893ce8543ab9ec6b411142dadc73a5c8d4318ea84c92f1482f3ee4c83be1db4e4f24090036eb9aabdf351325fc5865a36ec5b9d8fae372d8e5e42a97872d7ff6161ccbcdd20d56f7328bdcffa2090edc7fa952da75dd796b3c24f7a505acf739c62babb1016e67198d76ee4f7e1fde045d25ee1bab55b3494f55648df759e89e867da0cd6595a0916a0714905300000090772b55f21dcbfdadc07da90c672dd84e3eb7b887beeb448cc1170d05aff5ed6d2a0a67aaa36d0b76ac95acdde219bc952afebb74bad19640888f01e3fb2bdb8aaff26919e5b4ba2963018294487653341bc08d07c211cdea452937f2a2398917bec1a4cbc26f5a7a276f95c7827955e71b7c0d5e6b2836d8d81506520ed72933ec1356eb0e86b950100598e01736e87000000e00000001bc00000090132d9159c2693b4605031d9d3a8614931fd0db820cff1586861610a76845ae37c482268160a392d9503f26c73e4729eb9ba4e48e81ce46acbba5940b5befe62746a0b0d404d6d2050905640ff7ad60170968822a7680b69074574389dcd34b1bd979f232d474a3570a95c3b2720db7a31ce639fc503648592f9b394d65aded02aec9957f94fe094920fc061885fb59bc00000090dde8d4d0b0994f657c19ea77b96c20bccf7b42d2cfc40fc66500b6bd4b7b16f72ed38ee66714fa0727b946425817164bc9957a9fb8e5f742010a8b25824fc0b59941700ed1be933747bc2f18b35a4f01192bb2cdb5e56b6e94f90de95f2d9c8cfcff964523ebe0d4fc7ce9f7ea3026860ac8cff5739701036d90d352667aed8db6aeb4db8d1fa8e6089884c62c0156f8000000904153b073474c5db528f4be51601df0112a8d4d4ba2f2dad5ec82ae03437fcc1e1285f240c75a7713643657728145511fbd10da85ee19bb331be6067e453c6ed6a004eab94cfa133987db6b24fe4b4b5328f6d5edab27e61ced83baa42c7b3152732865ebc7f220b1f139fa6f27d2e05928f542135aa723c11ff508b83338960cf2e075bb43369b6ed46f309ce7e2582b000001bc000000900996b066ce34966c5fa8466a75f45ed2238062b136cda336793b7282c677d084bbdeca74cd1e06ee73e03a4b2319db173e6355dc2cf5eec9a1a0b85dd39b9ac260f7cbc3822ad3891e3c993c082dbfcf1c099f20d14abc5f4eb82e6dd7365592bafeda7e046f7f0396ea4a7b92e91d0513745d615ecf41c7bd8d130985740dff55a3dbe6026a5e80f8ce6951608e9add00000090ae6ef7a3a04a06aba48c357353e6c650967659f01659407980461c4c74de0884f0710ceb1572c65bdaa13b1de3c7d87b2d7ea4c5e175443f499cdcbc419fc4cfc9a6ddb7f4203163cccaef1746833ec62417f587cec58ac40abdfba21cd2add2927c04a6a95289d9a28ac577acb8c595239d5766d3d4c2393156ecb2a13f9226fde236435950396b6a56ee1870822fe100000090f5c8a05db5087e5ffe39815fcb37bacb14bfbf2e953c52772196959a95d165b703dbe921570b16991e99e15b4e2bd68396c4db8e97f4160356add145b3e9ff608f530f2fa55f9813930830f8df5a148e3045546abafd7f81a231ca7b975abf2962a5dbd88b969e5690eedb26ce4d3f30238b380c78bc2d1e4d2e5e919969cc45e415cc276965ab136d16a69cf34758f2000001bc0000009001df829a357a44970ee6cc4d401098330479eb359c3f69bccf7858c574097b6534bb04d7e3f8110b15c79e3d77ea1fdbefa57dd532ba43cf31660e9d4d0afc5b16696f5ff10e768ccef3128d6cd4792909129b9f9c4fd742f07d5a5033662d2c73a0c29d3a3a120535b776e0371fdb32198861115ea1d29ba8d1d39c9a36ad5c70ee0a28366ca0b0590c87e8b5b1453e0000009051c19f51f06efaeed558e6007aec37232a35fb7b7b54799b265865773dbe7b0a0a21282c2e7117651bf2d581ac8b040853c9a1be9b691da9d69a81a6ed5b2f186b05566a1faf567297233df82c15e9b515ec50a7779d8b2a2ce03c230e3c9131c6fceb6ee0257c924492c071100715422d7393f65393f3d52d1a2713d368bf37756f50a18bdbd23e4a7c9b80a6815e2d000000908f2cf32ce81164301b92839f7f83a03f1270b5b93eee777ef10865560ebb475dda85aae36d47b71dfb84331af504fc7e85ba2691d5c08719ac8146c349c9a628e6848c67f3a94d4955e7e77dd73439602c8baedd0694dc98d7b7682d9a2be35064f90b4cc40d6128a1629a383a63e68b10477a7c93e1feb16d9d01f28250d981a0014364a7eaecb958a9e0b8e1fe2794000001bc0000009078bf82480ab9af379874a177f5131c5737a1d315afb04bea2abe470b5c8335c41de1d90ab17530cfd4df0c0053968fe763c4525fe11d27e3831eb0dab5ae94a051be0afdd96c5e52bb00a90bcc7240f007808aedfdf71604a531f3106c8b532736c54d7580f5db68859c9221a6a246f32d0fd2fa766c225e76c431c23b15911c72a6a449b8b332d59a0ffae46065d37b0000009079c4088b4916ee3eea335fa522fb8a2c817929f79779914a6d70bce9560db262320f4f35e377461640fd8f5ed83a8e2c1b6a571b50dfeb335f0ec46eea761e1255947c339d960afdb69f462d4b4a96171f4c0ee5369eda087dd385d3a73553d8f69a66d3cc981513d3f7b97ea277c7da13c5ad6625b3719cc9922a33b900d509372e65685073456a9689d8f3e671cf1c000000903e43310f6a0f4b45a417eda3bd54c5655b6741ce1bf8bb52c759432201cca9859fa2bcd9d25c38eae0a2eb724da6bd423db952927ebc9260e130c594f2573729e52c01a8608786d48ab7dd4f9539f1fb13dc2590cd703450457b7f2e9ee5efcedd9bec09482778efa1f2452087b5ea2608c16ede459ecf2b771b8348b00febdbb4c743a887bf22ab9db65591cdae1ed9000001bc000000903df172e06543a3182cccf2a11084765c3e6bf28b0e0b87b78d4995c5262966bf6e76411c6af26edb7ff83135231bd395d969a78aeabbf1a009b1e92aed0d46bed700fbeec8e60bf18f004dc464e29ab425fbcb2f9ce3eb20afa7714cfbded8ccad46c7c6cb6631a19d5305878f91e6650452bf6b77000046d7e5acc19362d74fe0d1d7cdaf7828e4584e8c7ff5db0a3a000000900e7c0465de744c7dc835b984858450b15d0c9068d49213cde3badeb7b0ed7ead242ef5fb2a36da2327effed1d6e1546ff33189c5c9d8985ee21465891e46c287cf13c5fb8fb5f3706847bb3b75c11b52156bf5b51d8b7620e6790601927a544c713b70db2740e3d511d9fcaa5f6d146d00cdabd162b35f6d7f4f336e4e7b33bbcefb0a8d120108dfd68e915fe346a0e000000090ba5272498ab1c5001f484d38a82b91f3a255d7a5b0bb835742379750c42a449210c814730296432e381eb32d239854ceba60841a3e18cddabaf0c128e9dd673197d0e2ed6c6431cd52ad32a107cd955900cd6b3a0c054e77edd28d86860c5f63a5c48ee87f9b9ef71a9b3a72a01ada8a2490ea1c08b5b48f642f4db559159af3dfb462406abe387e350171ed76abf47e000001bc000000909d08c99ea2da1e2e868070a52b6717503ea37b1c4a801458bc5a5090b2d976e9db9f34b3807f6b9f066f6c3db6fb4f7858e31209b97e6552af165d4f144a2b92d4f677db6964c37dcdbc6b8f2ed48190073dace76834a34d319c7c8008d07e44640bb1db4b6ae72c174dbf5f59c7e304145c4b213d5e30dbe7cab6c50ad3c43ac5df01bacaad452dcd852eb8139027c1000000902f2f2f4042bb83ec7c71440941752fba92929c70e6bbe524fb904414dfd4ca683490c74a9b707a8a94de43c7aec160c4025390ccadf8333c5a217afa28258e83dcfb7c085eed7a5cbd591cb316bda6d60db2c649515dafe5a34157bf952a8837c0f266e9bef1e8097c774c094a1e3fbd221c65fd93c3ab6dcc3a4c72e9c2b51937411e9e935f0e368a8c17b722733221000000902ba5e91c85c88efefe97256b0d2a285261b9f3f766ece5e6ef0d19086b13f410bf9a24df9f0cf17f3abc9fc8d84145ee0f0c05118ef0d0fa0d99320f5daf8b1307513f7c46a8ca355821b98dc7e409a029607cad1fa4290d08b0f377d632e8309fea56003f2abc8f8232157eb0f99e831ec90c50c5c0d90609f5b92bb81cec93f57ebf2e8a85934958ec194a27919ba8000001bc00000090acb6759efa9edf780a8696476098e2b0e698d37f0529cc7e07771e20805ce183ece93a6d8220fe5e41f8f2c4f66f7d7600cab1e5a432239448a4cafac2664f29706b686ecbb9ee7a585e07ac328059a402ff59578da4e6c644f587093d3adb925e26aec2feb8a0ca70a89f09e36c627a07281794087566010deffa8026376f7486b6ba38e3f754db746cf74194a4650a00000090cd127b6b398aa63a9a73b1761bc918762593612e1270efd742b9f44ea325f6a290fc37ab2e78d604f3474b42314cdc14f10515479093ac62e7fb8009218217d17dc2c1be6979425d1f99ef36d05a258e291b3a3cc7dcca71187fb2469a8210fa7d944673c6612a74f7fc91d0d740d4d2201bfd7ddb9f169445c7852cfbc34c98457bd126da955e97f4308dc91310a9c600000090e9c97269047e138e4b47b8cd15b47f75db80aa24ecbcbabbae439e4af1f5554eb1b18500ee95fb4e5fa9fe8fa1ebc4b2352662ad8e557221c17098a3323418c6a5c6e209a9eb3ea6150a37bc5a1aa7760b77664e65a23da337ef538d13a8f322ec6c0cacae03379328a80650cec29a9705ad4a8c798250af9cf409b45074f75128973eccb68e627e2aba87bd1f35dceb000001bc00000090090959743b24692cd5ea95be03a90fe28eddedffc9caa45766141e1a454ae3aa88b9b51520fca9fe0ccab25f78e313a27df6c3fc31ca535fe4d5ecdeeb4ae6cb2e9059afd5036c342d0998d511a835b21e9baad20c0ef3c5be298e5273eca51df8041d08b4f88e08fc3695bb7d3f126a11b4f9af53680091d66168b8b4b2ac9b112d58df3acf91a5c1cc86e6f488c65d00000090d05387d02c443c7363d680111021068fc45fcdfb27d26f3914f05b48eb73dd6495e00c8e192dce422f7dfff826c41e7a5c98efc82d56ec2a1856b46fe18103dfea5b416ea3abaf2491cf6cf960bc2e9f1d5203b3f2410b36bc309f7fd06467953553d215372cf74ce674127ceabe66732d1fe77f64af1c2e4118d09036bf5929f0339a26128b5310bcf267147b085f6e00000090786c69a19ad57b5675bab6576b4f0fe2d6008f0b8e96b4a5691f1ef61b7bd2d3fe369e73b7ba2a0329888bc9a05d4de7315abea648c97744c02cdc0247f9477b634484f3e8daf469c96cfe6e37cd850c26640cb55b63489fecbcfd9688ccbfffcb4102175633b6a5377efcd0b7cc17cf0087ba0d1653cdaf6c68d49fa89706096ea2d7a9c29ad2f3dd867d1df70859a100000e00000001bc00000090a3876e16ed55d821d4636554fababb1fc42d06cbd92febfb62719d17b0f2bdb03d139f03e172349fbb12fa71876e71453c43e13ce97c64f8dbfc93415397633a065a1d515d26b62f3363bfc2854f8bfa10ffdf2a4efaed8b701374ab7f1e679a18ceac9c210fcb9acafb8cf37a73251f08e844a2b2001c82544d3378a05a9549fc7f61910e88cf90347073fd6e82835d00000090b5ff3c7f2f01945fb574824a039d5c8f42610b4a22c8b38b84cce82196b2f2ebaee6887ee5b0cead8b2d6869905cee40342c48e8efc6c2e9f832471f198074b291669e0ce93ba735756fd1c6fca3ebac0aa462812f3112e86d740a2664453eacea944595a408b3d4d8db332594fc5a102aad8663729ef614958a89a8b811cfee1d04540edf80cc168052d388469f0e6000000090b88b5d5719cc71eb2bb8e65e65d5432c51017975c69c91239547519b9e3c2d4628f9e599498bf8e302c4db9d1dae86963a18265772c4779a629a902121419e70a44cee9ae1129d1655e1ac4b1b25df362e67bc16884a13f79792cfe62a93585e14f29b2afbe23f15d1615f3705caacbf2d349c9d6a636d70237841d62796d49e3dae9b0c72fcc3b9bf91180247730568000001bc0000009006c722129a887a0e14bbeb91d2b1daabca1e3ea84f6c08eabc2deda6f75464cb597e5d05d0d823f8bc5f61221a336a976d225ff6fdc4a55a1fae420affad4450d1188825bfd87cd9ff4dbf25801900fa19518a80845efd7cb9eda2de5ea170cde239b239c07bfba655a5bb7dd54b5898210957fb956ec97b2dccb426dea1f357cfd8cfec662257afa8057f879a25c8f4000000905dff93700500f84c17a5d4978e2b0919e31d688d946279884a5cb09846dbc907b40be46b703041b02b2be0b1816374ce7403b92d14f4bcd334a1ca74ed7deb0a7d4a424a18cea800d23aac41f4e319a405f5aa27f508471258f487eb39b1289d102520641b12a47ecfe0d755b9d92806174fdbfd263a80f130e1b44f98423f769a15417b3298de41caf2d78f00850f5d00000090bbfcde9b17102b338768d92ce80368c9a2f4d6949b28be3a44746ed12c0d9ef2e2b66ba398c6050fc7c37ad565242d970e3e439bb08ab9d45dc897ee4828ed045dc4d2b0dcdfc7014e47320e70b14acc1e305b0d9424ff136843f472581ae3891bba2a8452089e70533c2466c89e403d038a8d402008467ee4577d68b2f14766370abc09c249eff0f906d0d1e093b8ba000001bc00000090e31a0d8d00cb9f8fd05817acbbde48215cfcfcafe44646c8d1924850509055c24fd79df0cd8715464e5a1c9bb6cb1f3a4bdd663963eab4c0752aaa1cff3a7b2eb75ab40a996b93f0f2302f6ad963806d0c503bd84ab49a02eeec51d263f1994702f69b0695ceb6cabeb7bba3bf52ad83237badec785ab3a745914806e6f26953a6ca04fc3d7cd696209bf5f104f86ef100000090063f775e7ceb26fe011707735a2e5888e7c230255e25e0979035744f3588eede48b272a0cbc80337c17972944aa6f28f70600506926e61c7630fdcb977bce23d8481128c814a778f9138879e742136b00d089f10d3d8c533045673b43b77fb383b4e661ace6d8d0162c266fbb9a6ee1d1dd8d16898423a2f00855cc213ce2d9044deeecc20a7ee74100ccd6e15a16cf300000090c9f9ff48464c6f94de4ed0abce66d7261db88bbd45ded714b66fb19e5bb89ce727fced3219274c155a314dace0bae0180fa8ab396b989830bd01cbe7928ef72559f89ef4d3d39d77d524a36e6816df1824dbfbcad5773867833c941cf338b17473bf2b82dbbf7946637b68009a1c0e1d170670a34b5b36d17e8dc7a3b901b710cc234ad174728ba4a1a12cb20ca5caf6000001bc00000090e482d47efca5ac34305cdd7cf1e0357dc9a3702db439d0ec32a557be756f27bb31464cf5a6fcebd489d99a93e23f8ec3bc9d6907bc21581d10d66a551180a5d13cab0d2bc41d8a1f6d2352bdb9d51a042d52113e3b937d9964600d48e6d8179044be056af36b7d28717ec773fc116c53028000a5f29c579fab1ac3a2b8650800ae68ac9a53a1f275c208c389013bba6f0000009089ae58cc01b9b4d1988af7aaca738ea51ebe24dee59a27948325a1cbc58e4ab31312369e2cbe9b0b21652e91072f57dfdbacdde7b7b6d221b3ee1c26d55baf5fc7e667b3574a6deed960f1522669f71d13566e4e0b0112c5a12585f5608812a6c602f239e99d3d82ca640ee8eaacfd080b4d7398bec0f577cf72403ccbfbe2f71dcf9ceed0499776ed5ee0c4957cb4c600000090e65d9f202a140c0a2022b6225cf2558d3f5a74a70aeb12acc459db2ca2d3e1826a9a37e98ac6b7c01a555e2114f7951822da3937d011c7a2cefb4c1b94ef44bba2529551281404e375a79950501261b01268dbd966ea9d77da87d9fe434442339186c81fa5c2dd31dffe8c23310e7d3f2a4f8272093f358c6b080b5a38f487a72a7d704b32572c536694618194172be9000001bc00000090e4466379aa91f3bce88e053033ebf202986b24940b07ca54164f0cccd41ca2521d2f1006404038afef6819f047d200d8f16b955629c7bec12ee1c5270f0392d8c98407c12448a429775bac3aad5cefa004872024a2b68eedad94e7663e2f4b21b4bddf32d138d844287cada5ee2dce080a36a7e159a32f219ee6b4e027c82ed2b456ae6e6499b13eee1581011e2e6b4400000090e3038f011ecf8122724726fd8db040ea9e24b16589ed2635f3751b1ade8596162fb96587ae669443d81dabd555a5358cf2395769e1079e10b467b9392e72ce23c810f6ebb2afec33762c8929f7b08f5b1883ccc2b03ea2df7dff0cacc8a2b9d47c2cdfe9be11b2cb64aeee7b22bcb2c31030ab1e56b449cf77bf7341df47fe48f089d5b0419675f8ff6230668da522000000009034fda1924626a90d62ba3a0e77560c6061bf610393bc208e92479ee7a591552f2ef5d34b8cccc41e98566d095b477b6f9b35a0d77db66384489d2c5b759f9b922fe8ca8d89c1e019c90a306a9b228405213482b7e55ea72cfaa28a983538434189af956e90ba1ae65146b08d92d451681b452d1ac8335c202aff95a6f01d387e9e377e313889ce43777c5c0d4915995e000001bc000000908300f26d3083d051387eabc1fa6ea58ad6111d5ad459cde12b4414126838bfe80feb66f89adc287849b52e352bb159abb21d7fe5b2f96afa5a56ac91e2393a7f43dcb867527e553df0b82cd01ea1f65110a950eb54c3ccd5692340d5e4e258770a4c4f5c869fd017c55dd539801b691f1657c78f302683645f577a3811910cbdee1cc7209049d3b1f23eb5d8daf1e1d0000000908480b44d561ea59bcbdac63423d63c3d45b314fa17cdac18a35f02805193dead44d1675d119f0377ca46c6625a3a33f86eb2cb6ee6ac03b9311690ff2d4ddb5670d34a8a577079af14339deb75c09ece1dd33cb17fba31c4deedf7d37ed1b5cefda8e270c3e3883370bb8285fb8fb7dd1527cae5b86022bc1d7c1745e0df1cf1c2501c3398051375ddfbffd4d5ec4c8f00000090770fe8024a65c310145b1edd9638e65b5cc21a4fab5427ee0d5a529aa0f770e6a209dd8608d528210d73c37e2159f2774716cbc7e0dccfc79e39b6b53b762034e77d067237c1de74766583c1f4484ba3064242fb6cefd1993cf4bbcbab8dedda0b7a4546e17068512ce6db5b71e8fbc31cdc30adf2e51dc6858b4865c5f96d769aa34ce8f4b63763d2e7fd0afa3ed132000001bc00000090290b968330d9b2a6a8429b395aff8a353dd65597f38f50ae73c75c1e4b471995b3b23d3d08aa1f5ee4a60471053d1d78fd50a24fc8f4829b43aba4604342c1080a603eaef54b1e03c235f151f8a635be2c715b158619bbe48a16f6201dd37c0323f59537e0e0424c2bdccaf24c5e3b2124f6275ea3f9ab4f0f3393eac7606405653742371717aef2bed00c867d5135b800000090003891a78d433b9cff782fab1b12d3488d4d616f84cac4d51ff1206015f7f2bafb9309521c5425cedf5e4a054e2783c4fd49b54f0c2758c72459b04cf8f3d217ee25ff6369aa0f98a8a1f28bdddf165b0925b0db8f19a1cd1528dd5863d25ee007b07e136a6bbe605c8b5ccabb4e3b8025bf5fa4eba51c3abf2116baa338643c472c3f67fcf8f86ee1225e2a68acb8fa000000906240c30ecc2e1b81aac6375b7624902e826c7ef31eaa1edbb328de81fa510d77ee3984891fa3e065e55a11422a20e7837fa5e2dce0fc007b6b42349a70fd49ccc7103ba8ddace83f4b8becba2cf709c41e377e7c37de9cf6937e975277b598a1b1ed960be7f1cb1468085246647c5c6b1d305e6c6d0704f6045bc8d0ebef9527ad356e325a7727dd1981ae243eb00111000001bc000000900e29e1361514875a00ff70111ff79784f25cfdc3af735a5e7b74e934051ac4ed1992c3f8578624175065276893f775acbe3ab7a307f6352f37128fd69088715466745dee45361e1943a1bb42c79a4ac606f0dc81e6229de80293a839449cf77b84e6b595e9098516dd479ce5ad0d99680a340e7809afc785e4b448a669c076c11aa06f70830474b808079396468f886800000090543bc7a8713ef2d048a6b7d3cb0420b27d2ec2d1cd4cba84c7f8dc2b278df74e392acb5ea8f63992cac9d830c4c41c2558dd15068d18772feb80b7fe078fa12cb1ac04bdcc5f1f13d703b8fae3e1d9391bdb20c632ee66855a0f9797e82e2ca6c8e82b755fe7ff70343360b46364296715903c0f9332b38d5c5f82d5c2678b7be0a1ca117998466b08683ec43f685fea000000903d102425c2f6a06dece97ed3e1024405c8a4b6c80704c0107dc067e4f0ad0dbce5a9c66f477d45adc34a0c6aba10bd89ad720b07508710262f0bc332137a513b6ff63a0de6dc5d1c835dd8fb7b12f0072212f1ee47da9cc45894cf5a987c44bbf1e3d4d135d391d04e725237805b4c1d01c79918589ee1a68bdae93bdc9cca3150910959ab78f4ff7eb936689bdbde9600000e00000001bc000000904f9a864e690819a00fb8224e5d3155788abeefab5507e780edf2a71530813c32f89f2cdab2818b50834af7fe6db96dbf98be1b603550bea8f83ee2e9ee48276318716e1b76c0d7ddf83b13cde5c9b72a29449b6a53fcd372c9435bd66bfa1f1e2ad6f334452b04ab28e9140fa760652b266637eaf4fd6c15199410e0442dfd6853ad8039c839cbc38c8f8a641b4557ec0000009053778bd9d306881e6437f02d1c060c6ac911dc6dc08e14dc2fe7d07707db0bf6d1317e435d10bbf694eead58bd9f247505f45d2474764f9484f51aa3d47b9ece0c873be7a8eabfa750681261208a3fbe1abd5040e0f3cfa195fa47e57c9eeef7abbcc9e44a7a410b8f642a7f73172398091c39940744b315f2bb1aa543bf2300b7df1f145e51a9ecbdd7edf6c1f940ca000000905f8c5f38e2cd1526e302f63617c4c9442d7a701e64f186f4643495bb0f2225f4d447161caa374675056fd347cfc9c326abbcddcd2dbf7fa0a7c65d66a00c9267934cf5024613982dd220b5722e732f2b233018f448a53711c9125341245ea58ccb0319c067fcd85345e2d7c01ddd145017d6eb1fb8dca36f5aa255c7d6cf5d0fbe53d2280505061a10fae56a8037f9ef000001bc000000902d323435155354833a8968b946c70a808c7e5a0c957d741deb6d5e5a8de5a16c9c4e919d122e71018820419b3bb3ea11bcc20004fe62fea8d2ba9fb60fb876b820cfb3f9b1e9a4b150ad8e068ff23c2c18eb725ef932f7edb2f127a03e5f1e6860b836f2bcf6d158b5436b373e26c3c5236af647d18c743d8f4d0cea5c99dd134b47c98959f3e21dd4d432e47a953b35000000904550746a5407fc155dc61fbaa7fd755c1eecb77e8436f97ad949b11abb5620d73e5d8e0a4b17f134538a6acadf3d0dc4002abc8ac8e3346942c62d5987689524de70ca521b9138cb85322d3d139eb015024d269932c7ed0293cf0b10aa5e4fa1aed8b334bd2da9538887291d4a45908123521208b53e8802d8822973c96d095d142847fdd2647c4096490dbc21b89ddf000000909e6a9f692303985214bd3d440f42da18221f968a9842001de8589c9cbbda59b89b0f072eae9806c576ad4e5d36ce09dfbc1ce7192fd51263bea155056bffab8c1fe28c1d7df7cfd69364dfa06463143e1c23fa6a033cfa7aad7ae3d3ff76ef9d9b02db4c233d7e2e273e1363d1aa88510e897831bddcc98055881aeb1416d3a6b7530b777503aebc2e54d6ab10c37d0e000001bc00000090d58a0acfe904837b752f41eb33c3d959affde56bb5947f8e20696e0c68d4e953e8079930620497ab7e7aa39694f7243ece745b53d450678e9f989059ce3c00a2fd2fed4851f4a2981e532c924a4229080d331f051722acf173ea3580dd246afb3f540af9e403be1f550f4ca957ad0ac10fbd4a4d9a643a1f0c6128d7bf44ad7bff2e84cc19ca5db71575b9b52076e5c50000009097a819c4b0baca0937186c55c7840fbf353123c45346afb6366ce03ed1007e6cc6425341d00e7de3f234963e14b1f36990d9a08170dae6b366243b9df8b9ed34c5b9c3752428ebb827164ba27345ac88268b66690366970da8019354582c203b0c91e290f71e0eb314c617c084af18c718f5896b1fa2e3be304b1759530a4b0da0a57d1e5e9d94e96cbcff3ceef39af9000000909aa7ac7b6e139c864a92fc2cae4aa465d428eea35dc90501d60b64d527b85c9dcf116e257495f8f3e4b5ff275ada7c77811fd81e16090b33968a7866f94e4b9e1d1ac3103cba4a1a96cca7a145eb2a9a17c67c30e8843e28fc74702e7701391560da1edf7efe2ccd6548ded4ee8743fa12eba27029beac848fc5cb5542c1b38078ee96b9ff5e44827edfb6abc1ef8c6f000001bc000000905f457d742ead95b5eedb9b948f86be096590d0e8e112383d744ca7ea0640ecb703cd6a42dc251d0ac50a65b6810a2a330524cb21817f1cfe8ddb5da561433d545ca5d3867cb28ee6a7055e620f80b8b40f110d07b3e07ef2b58a4d7310ccb1c9499fd0763aa7ea99229b8c604f28ff02083622ba713712c31103eeea2e1ab0789f2a3fe03d131652cd452fc538be8327000000903b8939cb4709958428dfe265eba9fc58c4a72c3f3f9a5d685681f1828c317d44769dc018b8aa017c3f8a4855e885bbd1b9104f4e12dad6554c86d6e3d68e3b10b81c1ba7874847edddfb85835398930d2e965aa6f1a9348fac83cfd8907d032082fa1832f0e6e9a3370849fdcc2bcd0502c306678c28645be7661b14f7d195e89dab565d436a55c63b9874b820790371000000905ac1167885ea7eeaad310ab9384ef3a85345c6e10bedcfa00f0eddf1d2186ce76e35d94dee3701f21a340d6ca6be5f5771816c78dc7d4d9642a0360f373c273b2f85fe07012da5142754ae9b4c1e683115f318b02e54319c3eec0a1f57ed259fad61b8029918bb04abc88d5418031a472bfb38eacb9e6aafef22d059b2cad66bee5f27951d7653f1d5e6a1da7d7fad25000001bc00000090186c54b312de2502ad90df9d21c0ce039879cb91c919fd22bb38cc261c79c3f6e465013bfecc988abd4b69df333a8f616787e0280e4f87b70a617e4cafae0780bf83078216e35d3d331a1ee4ffd020ad2448a59aeb1b2758f92194e6d3b81afc33f106d6479295451e96e64ceee3e51b1b94bad364c09520d6cc5227c50aadf85f82e0c59e7a3da5967c45f9292f4e9b000000902ecbe834880fde873379b8f70e3f0de3ada567546eae1c9c9af258f4f3312cfe439ee227c5748230dcf227580b6072fc17e3710b4f156cd877bf40f88b2ad26955df72281a2d2cc0754234c05978ad8d0acbadc8f9797ad222723847294785e8e17c28e183001d281a7ed57aebb00ab9016cc25d4e89b4fe2fca8c6454acb10a7ce5ddebd7186f0dc2d52682ea2d4d4a000000904c5c6d664fb12e3471d405a8182e87e91443bcf78b545796e8c73ba29651af4e98c2e7a95c9a9c46dd5d3c8df95a0f5439fb2b296cbb8e7464ddf15c389d2d235dfe994da79aaf9cf6891e8efbd94ab51bc8f73bc8f10fa23f0bda83f9be9e76c25e2af740f2bde9b5b0a0f76fc5fec12e6d9e7203dda27b27eccc42fac592fe6e5d51d991e51d12223ce89f4394cf1d000001bc00000090eb34f161278463b602e60cee956c56a68b4fedeadcb8c77685bdef0b7ea3481ee297cdc07da286af421064251ea71598cab671f1f4996eb1cf176047a6e89c2aee237d289d7bf9fba91ef7799d8cd9bc0f77b2dd8a32a1f2be262f3a001f8cbf4435ef612d0072197f8615a52ff7afa713cabbc93c14bf0200295cf634630cad118a1d988bb10fb3c2814e80a4512575000000900966fca2b9d5cabde2a66d5c70d08172f1703507d741e7a635a4927fefc4ba2b09ef5eca8fce696413a95cd9334da60f7a9862cada5a9fbd788347dd580e99caa43968a6255f5b54610fa3569589a1690144414c7ecc579815de419ef0941b4937da5977957a745d6796ad2aa1383c3e2efec4365cc356b9041a12b290c5d43a3f3b1d77473d597d8a20f23190c05952000000905ba55db35d62212a6e561944103eed603ce9c61a94f386114da015a7d1b89e44aad3a53166f650e9c0dd8587de37c999d8a156b9e17e75d24e0ab4dc413ce6d32c62cd6e4e6290d2242f416c7120b4501f5ed62312005fdf126f018799a41816ff5d0f2a7d572b3af4b6b1d7e7b675931c4eb811312060cd88a5f00013e1b4a3d76e5eb6b433b7decd9525b6ac310678000001bc000000909c5a60a7ea583c9914b81f31779c244ebd687884e42d9f434375722df9f47688056b354b5f02d3130b311b15fde7e71c1d0f7b69135a465394e219e1b0f462b8344e9ce29b417141b88b358a52dede49157da2437df6eb92eebe8edfc1098faa7508c414e5e237ff9c15bfe6d54eee2e1379a4cc167231e2594e62363d1fd43b809995da5720160806ebcad8476c302000000090791a797d26384790a3b36b6dfd89684f28427ca87c8ac83c136294e62cc7cb7a0e2ee61c1c018fb9f78b843380e12c204d4c682289c156895077350ddfcf62fc6e2ebba789d75a571ada468b288e1ae325d5b798db527e7c154acff67a5aa52b91de9983e3c2babda6abf48826ed16be069fb8d5f43234514971c56160f0eaa805feaa5ab8b4b7d58938ac565f95ebc400000090b491cb9ff91c3aadb441623a1b327ec20de34e448ba16d5da4d6fccb99ca54d5c80a8e12ea9d9e81b94363e7ba45b400cfe959dd46886dbb8bd09088761f5b757b33f2449a59b691c5e43b83a89199780696c2991cd1ee09b637fd8958c78579f96f410cd08acc37882ae9bbeb01a78a1f8ce2cb9c1c44496e26f1d5eafcc825b6e36e060aeb33721ca8254c18c3f679000001bc000000907da33c299d26e34eeea01f006a110d5eccb3bc6ee359078ba7db61822c4d330f15fa724fd856f7c52fc1a1b159e48854fc4acc31e2441a8166c09f41a36e28ec4d28fa82d26b0df515cb44877d025b4e11b074afdbdf6ac54b501156d075c5cd2e335143b697d8569bc3f1649971c5ae1765b97b1f3110f32c247593b11f0c469a3eb837b01acc06cb42e7931a81c8f900000090a30179aa3af06f3d0af1256b70daf420df531fd45f1e5b60e30ca87df4a566a56cb04df18e8dc75c574c6159d1f0f1d16a3099cd70523df46ca4edd3af1700bd81b12d34570d92c895ac8e950af5358824981da13cbf6d40b1e6cb7f6ed01acdb38a2e1f8289ccce83fc22f98cdcedef16d7c75f6015cbde52df1f8a398883df68f7f9b83f6ca7db9225d10642d7ae55000000905973c0c6d830bea7f2109523b3a3f0e8b3a0805103f755cc55508a06e6ef0fc44848d1a6cf36ec4457b2579d800c7431ef9822db5565036654354475ef6dc5a4cd3cdc5b0b594dfdad56a2a0c7dc59162955f7e27e655fad747e137f81280b1491cc7d54cace55f4cb97c60e7187d43d1b304492a7615c8d2acff874287f7fbcfc083ef81c5c85e4805b0ffcc2c8cab3000033a000000ce40000012800000090d1905502bfdda3ae7a7ad5b8b4f2f0eeb59cc1752d40934520c727ca05a2572c2a79837c6fa647a2b0fccb5220ae8d669b56bd4a829b9c0378969a2de759580adb811b9a2f86eb5dc40eae174b3cef972ce9bdb652ead9df39d088644e4a8333c50ba5fbef3db0539f062a293a583a7424e214b300e6d33957cb37a88d766ca117901e7bf696bd7a60fc37e380818b88000000908a835e9e543b4d3dc26b5fe41a104021f8cc76a76dd6561a548208afee29332100a35d0b84337985b2fc71aa91c1dad221e06bb0bb66101d07e6751a1e6386a6929bd87e97c762dcb3a9813276337489018cfb72c40a18958c16531796042877664fe5967b33b990051f4fca9f81941f18d2191edf8b4de25881f851e771443597f13d2f6178afe3153201fc53e56e300000012800000090c80e2c8ad9f0df4dff2b3cb6b1cb64ba731bbac16c1afde6a8ed0d80f2065d89bd5c35323ef4289e6d946469dd2135c7afc8d2468e2f31531d4fb75e069e8bb47c40cd63642a6ded6a1f459c161d399f03217510b4e322e452aa0eb0b2e1bb5308b66d500a96d95ea206242f55c2d7910b72005d5c29786648b9909e5dd36fe31f33f04a1fb8ecb5a8020ca9b147d7e600000090b7bc70b9b15248819fb334bb519ca71b94961df9498d1bbabc1c4c6469ae6b9bdf953134a2ac9f49a77f599c80524b1fc19f09fc843bd99d52a0c33f0ef8052c6a6dde62a1d0488e02d3b32831f5184c27050dbb6e761e1a8df2d604278b19fb23bdfe9c178d2c7c076d804852e463db1b60fa77e817d9eb5e847941748a284750e9207abe6e05b5a50431c8bd6884f700000128000000905f665b3b5faff4c044ff5ed2a885d0bc4f22e6af15c3fa75e1516ae0a9b1105ae7e12c261118fbadd5923d5dadc6dcef42785069f58d10fa0355d690fe8a4b558add1498cb1085e6cf6f80cd22ee2c781dbadff6377db9efa8a5c3ca7594f4dcce4b7244e8d9597d4ec442e3b24466c2286ad94eaf7a5716277fa3c981ed52c41ea5e92220055d44b8d18bb37d410d85000000902c7bd784116cff39b2adcd15762380929ad0e311e8365944633b0c3b4256e22f12563f51cf6e7060b40a36ffcce0272451c19b5aa6acc6f59e422beafc3d835ad508bd46d6214382211a4f939a2828271c90ae7f1ac9db3e576b965e53d5269cb929a6cf72113430eb8dfc4718acd6ae03b44eccc4a1778e75156ef832914dd19e87fbf6308ddbde7be1d66a6e050050000001280000009079abf20bd2d8f39a4a63f3d567e7d90fc09feae46719f58811c4f23bf8daab3b8e203a8798e48ee553e517c1dc62bb7ae71de60d12b7aa26721a991d93d8c50eced62dcea7fea4cf7579f72c124ae23a2b9a9151b716671aa2523847c60e117137238181b391927c4b7ebf690c040f8d1302e5b280eb51b772bac3f1374c5cf0ba3a4cde90381af01f713e5f74a2988300000090d0e251b71d84b164fc2a5e92423d28a1fb8790716823ba4a81370d1bf80858e853be3ceb93c8ccd4159a1ce68aefcf40bc6a08978007e8720e37b8aa46326a818c4dcd5b45024a9899cd6f83cc74e61c195bba4b7c8f0f8ad74603c97fb144a2dcecbcf3646087fe1ac79354fa6ad92607b2879cedac1f78ec1f294370e26a2d3c99ccebe2aa6cbc11cc76bfdd99510c00000128000000906cffc8d66ecc763d1f9bdaab61abc993574ed1980e688551a1f473c3bae409ab6bff793f77c5c6243b8836035548c2152116b672a63f55681121fb0598f7f34b42348bdcf9f36e590dc13e39f75d81001f6e603a0e6d781a1aa6ff2e99e983e2929c8faeb88735a911d9a2760d28560e16ecfef2d1bb9f2ba04e5e6b3fd7c2c55fe03b3482bf4bcd253f9cdd882ba97400000090f83c9f1275aca4c32c8d8cbecaccaf943fcd9dc2ed6214c6d30139622e9a4ac84e3a83b18072fcf6b43606375622527e275ed31914205cdb2e547719a8f3a38f734e31d1a0321098613ac9ad847730090fb5c8a755c78ce7801a217c95529fc2f27b12032629ba5d6dad5f84391e150613b8f2305df4b0ad9f80d62f383d76ca5c380c371f688f9009e1e18785ec63e60000012800000090129dd7c39bc4e543b4228ff3cda6d81602edcfcef4a76d785d675661da95dd6c5b6aa104d9c396cad8052dd8e2b0af4d9fd666a9df0cf18a71495704943e84768bd1536ecff3b070d774e25d8abba0ac118f9a46a272f0a052925512be95f59604198c76999f730f75489194f0ee50620a1da9159d2c2fec13f4889ff2504f1e7de758a6706b82430bb66f3df68d73e3000000905aac7a384a7eba4c579bdbece9546dae1d26c942d4539e00df3cf77b69b9ee876b91d63b196c6c4b4ba1bc9396a1d8c48dfcc98bc701d4c0618ef54d3e1ed188447ccdcd8d733cd051863976a2b5e74112f08274aee099890d0575139403bebbae791efaa456c5fbc66485add46880c92fa6ff5005ff848b61d2e09fb25d81d9e08563dd63740af23d49f41035a43d5f0000012800000090af9a4e40e8e108a8cdc3d51fa0a64f553948d41472a33c9466a401f8738fa4e8a2ae87075b434030a1e55bc88f6873f3eb61556c755008d7d00867ac7aa2a8041042c16d36cdf4965ee358af7c2e8c73224490fbbf16e53d62c2ccd7b1d63bd8302fa03838f25210693ca227678d458b13f4567ce36ea57348b0272a9145dac30b3ec73b71dfffb64e7112a68ecbabd80000009031ddbb3923caca21f9baeab0d4ec4b93efbd3374553474fc72beeb1f442fd2b5a67b020ffbf783587bbeb6bae515862f13699961ebbb671dbdf9ad5e5d899d74eb50800e72e41e26adcbf02b7ecc3e9e18f6d051a7d618e7a3648ee7e30a78033e9ecfb4ff8de40608780cd31820e0e6001da3eed13df55b1d49aa277a94e02a49ea6443ab81f04dee97d81762c9e5d300000128000000901fbf647989be185f76f8cb2576048070b5203f324130e5a2a4047c8ba5ce9f3ed3ad818d5b893bb4fe722d3316561e880518a6869b8726022f3bb75a1a3e4b87cb52ced27e8392d4bb5052f94adac58816f385c34702ec0280952432fe6446601176af2bc8bdf457c5bd3fa42839935801d0afd78d27fa50c09d735270053dcf43d26a76e7603dbc7016dfb03d29da4900000090fbd06a73bac0c4b1821816265b032d2b116b124a562628409313c3b0fe21651cb6d73be44ea7ce6cec081137274c91cd92c06f255870a549544f790c1ba7b9146d498c69526a08a5d21ba8d6b25d067e181ce6e311139c9f402f6998d3765a4c7c7ec592ecee5b0e0b9355dd012b96042d81a176d087d0237db9861f7ede02c1f07adadbeef2f419eaff709ca3f95c850000012800000090d7c2bcf98fec6893a4b74c68ad3a0309a5f71211c8e891e6b535eea780dc673c2781a48323f8ade10024be2601a81d0671032e74823f2f55d5b25ab4ca3bada178b7a981c9d1a856354c745b4afc2726255099142c0e31eb2a5da9d98adfcb46d1917b7d84e1e2e77d326987f7cec355112bf6c26d4ba0395ead9f0dce334a0de4efc64a71809810918934bbcb6a461c000000908d7516bbbaea081bb212451b528b8cc86bbce048db2d8c5772ed87ea9d4e728aa7b61c87c57bdd141c6ff39b05b503738d1d28dadf5371b4b060bda65ba3ecbd41be6ef111cf57b6548da2032f0a191a0bdfe1b27d90ceb6b23f04f8a5863e126d0853747b9b082b487198a4920872622af67ae94b4f3179cd5469b1c0bafd8c02b42bc8799e6ae4afb79ea72cde4f86000001280000009019b7e77c5be67c435c76291404bfd10b5b18466c1dd37f8a52fc0977a7bc31f7ea0173215fc5a448a2d24248a18fc60ffa2fbad7d8475951d6e1ec4462bd9b9319c40dfc3790342da046c6a010a64445226f2fdec5819a1fa19020cee7ff19b68b52e988fad1bca1c3ce88a74effe63b2269c7f78fd7d11a7cb61676199fc26ed50acb3bcf72666385bc6dd6da8d07cf000000909adf698c4100086a212716abd6261b4aa923bbf41c554afb8aae3198f79902d4776a3d75a20439ce0799cdaad64a568ff3aa4a057cdea09d83b552488c55c4d634f0da5d5e63cdffe3cc903cc59c80e90b17fca95c2cef6319e776d6ace7695299805c4f888d32edb5202a3f50fce54408244857ba5f6d9e700c2c297451d0ef54e0bfe991e713157d8e305aca7bea27000001280000009092e0543de57e6e227efcdc03e8082029df983f760b71e48e080644b0762ef393426c17c75b79b19eb2d987e60427498a2f56b3d71ebed4a80dce9b312f85db8b05bf9c3b1aaa38518115f75edb89ce3f0a5f1684b6f8543c30faaaa4cbf2c2b27c1769a0a0037f908652f979184d15042b209b37841e256d093ce675fe2447c12c71c9c1484a1bdf489438bf4f1baba0000000902cfd837a912d0bb6d432ab447303d975d1bd04938a49a0c7c64e5ef58fbd6107a46f190dd80404e5788c51979b300f162d1f7ebe4f8cdde34303cdab18fc449cc3dbb3ab5f4d4949eaa49f3749ef0b0a0a1ad2cab1db5b5ef6aac87ccfbc70ea6ee97aab13016f0bcaef27378c4b39040b64ab2ec04016197e4e9f022caa51e9669167200d6da163e5c2300e8c2d1cf400000ce40000012800000090dc587aa4332202c6cb7166c034697783e03233d9ee1f3ee7e1c6602ca72390d529effd755655c207151e09c767522f354e091210eeaaab36f6998df78cf65c65cb3621b310c6b6505789a52beb235e7e029d00de64046fb9ad323d2f31a6910ac78f3d69b3ad2764288711682745395013073a18139125a385b39ab54f8374c6ee1c3a75961eb01724041da6505c2bc600000090bd5aec0b649106c5b0b81a92f71e7f5eeb670ff3d283b008543ea0724c552eb415087e0d6c6f62f722f070fbe94813c5bef249f71e83f71d73760f7e5031b2b8750a949a00a8f9e342eea1e7ead9b8b11330cf4ea7d3dcb98d64b51c884b40530f9c27878169fa4e33a98ec717b24f9a2f668ccfa8b130e6eed8849c5d32fdbb945187c2b24c7bbb269370eda993061a000001280000009019a2be31c8796821dd876846233d0f72d8d55722d08d6300005ba90da68fe75f9937194533834ece95eb25b6dee9e6567b4b80daa63b358a785cb86c8f850cc669ce6d7d30a472e6fe8f37976740444a237232482c8055548f97b72df3ed625f0a4d0695bca06183965300db8badbf6126f2ebc128889d1bca33a6bf88e4806cc26e5966190374f94bfafbef0d21ac7700000090358babb9cb8691971aae68609d38b10feb1d2a8190910d7422a5bfe0aa58f0bc6783ed56287ef8ea4741bc1def75219b838094bbeb8c21476fcc69256ef36b84c3a9d79395aac2d19d4669b1641d3cc721eb517e6e92fc0e0236e950cecbf17d9dd8a8e9670d2b89d2ddb1b6bf65397e2bd643ee46aa88398e566c55e109086ecad8d1d56fdcf79034f6431ab924ec36000001280000009029aeafc335fa8e95ae74da73f71bcc7007c8c33b37711c8214e447120c37746dc97e9c65d7960f7c5e7320e75f79087692feae942b353a54f1165a16d120c271e3e5af74a1e0b9e0f1cd2c5d31971c6e1385483cdb8dd34906ce5d4cabf56deb0e276587c32de7c85e15e5bcad7f2a6e2940acd0f5fef55a9bc98c8aa09014379d83345635bcd48d908bc883c18b7a5800000090881a9e6f7e94e86575c91600d2abbe813a36c564df6b2ca8ec27b51e6f35a0bc4f8d68d5c4075d0e3e87a5550ad353dec40eec028ee1f5b42a520e1b139998f992df29f03daf9d3bac5297de8099d0530bf2c0036b5033120264a9502338f229edcb96a01f1ec2c924062fa313f6cbb02ac0914620a0d5a97e6ce1e9cf0eb7c48c7543a298759b4afb437d2a1dbc48e10000012800000090e5091f2fef0eb8df60f95f8444f9f7745dfa5d699d306ef4836c64e2b98268a7c6fc399564d4d49d1ef7ea4a3d6a7df458a3e257bd1393be9e84cdf4bad769a6f3c5f3c2150a019b0b1c4aa305f04dcf0fe6c8650f71f014dc1e381be69eea2f1e4fc0d308a81489492eb186a6ea3bc31e3b360147677cbce8597942a4dc305a1c485469a7e7920dc1a74500b62b819f000000908cfd83bf0d0ad99129f802f98bf4370798eb4215dd86510f6db1b8ff8c09f3581d2ca57cbe44d237277b457e605a67b76f8da1c39d06bf41b904bf8416481acb03da65940038a83f6ac45d792f2902d1207f03055150bb78d277e49122464c205b4d4f7241ba15ea532aa8cfa65024f40785127305a1449eac0603659300119487f5ef065d8fb4932caedc4c7221503800000128000000904654a6046603b6cc049242caa630c290a5f236bd2d8117f2bf709457025220fd94aed67dc69920ae0241d674e5fb16bfaf405a151c3753fad8f015000da5d3b0c6d4488ab3b2cdcb3cd53bc2c6619c6212e94f10e7b4c7b6ae798d3a04a2babef49dd2d2973facc3ab135dd446b124312471e6a515f341cbf69b4daee6ef8dbab575ce788c1334d57ac0ab27421811dd000000904a95ea082c55c5903663995a454090cddbae42a173c3e14a3e9466f1d4f3b0506b5f4e32c4ad9adb958e2cec97f906733205b216c3206986a66b55770876ead0bad7ef67b620af8399486e235ba7be572f3e3f38f9fef355f6a30c1ca79e2f079239077524bbb3965f19c9a608ad1bb00c6d5ed4acabe3703e614ee07d63f66be71c2602f5d292563a3f9375547b768f0000012800000090c9a80869eb7414055e9aa60e96f1426c1b26926be0fb1e5096140b52e3d9a33367e26f6ee80748faa5c7c8604e0d428b2af4650ac06e5054ed70bfebafe027c1742177bfbbf147042efa25bc3f4b0f882f4104e4968239e13bae19c0a2cf12b1516ef7d95598ccce1e7f894af04196a41f90e78c56e396e36b56d6ce04195c666002f970c065136b7e8380e6b3e9a42e00000090384c10ece0a90d1b7c7ae0fbc69549d807ee6d9e6639ea43192eeeaf9ffada9178b8f3539a0b5dda6ed1ffd3841f3c9227c46288aca019c1c78749a335b596bf13fbaef22250a906482065607bb0b8a72a5ba7f0a2ab4776669acfb5f68a5c09a9664a076b05cd6f46b31552fef89b242d893e40a89ce617bd3e798cd75923f34eede2f2d004b755a3fc0ae4cf811b140000012800000090f07b110e3bb4dd56f549b2e01aedb0b50bc6c1a46fbcb0276d3b680fc2d0a3ba6d07eedf092c2fad2b5ae450b2dab4d613f80a51160f3fdf345396456d13aa6bcaf2c0f81af8423681a92a5ade27d5e12a8391d3905270565eeb55eb99fd39011ee40586cb5b8916ebb2327a7f74228a1a5768b6748494cc156fc28bdb52d9ff1a396e8651c9da2c109175a460751d4f000000905c3bf40c68346b39d431671ada024f4a21e96d7a110953ab1683e79f49fb8ad7ca1b4a4471d163b128b70b6c1e2f7220e03eced83cb2b9a4c50e891e9c4d71700ceb04182913ad2c4b80c566592b501d1e49d7474a65b36dd1f024ba26e16ee454588b8aeecbdf4364019c0a781d121a04b1066d2e035738dcc00d28952630943a12abc1f9d4d1a680901544efebccd70000012800000090fc4a6fc3d816ba0a3885d6a7a901279f62af6dfe8526ef236a4ba9d60149099cae6b220da594b763964d15c366ae002c8316d367f909cc0033d132d4f22eff1b8a11b03c60557808da6cb21cab9d65cb2c1b4a28540767020a55bc55081c5227a5e6f949644f7c86c58b080d8ec4b99e0f4538bd25e6f274978b2f466f009d74e3376f76c026ca8e1bedda1f350da157000000901456cf4dd8e308692b2f994b1942bbf8796aaf378ff14a25903446fa8f070df54c78c017bc78c03aa89115f28f9780743aa738c99a0a150901ce43fd25fcf66ecb1efb1ebb56350b7cc4b86bb6c2388319532180d1c6eaaa938edd4a86916d7b89f43743bd9df883b58efdf9f52e1e350c553c60cb3b671365bde8451bac3f042d25f2c828a8c923ca3e05ce4e8492e200000128000000902903d864ee728289e1f7bf2ae5c9c2949b37d4baca2574a25d380863967a41d73889662558670596e5d322b22061e70cad78bcabd5c17daa5da2d530c8724c1170fe843d83a4869ff8ffe1d6bcb0f2a62c7b8b3e650cb59f6ec647609994e2bb9e96f03965b90f7f89e03f2724391750019e9e76541ec54f958c27fe8b037e99c7481630a92579716879ac717faf758900000090cdf542f37ff778bd9a658de2cf9d49e04f7648ed16f0de2a7c1a64c3b2785649b08baff74fa6cf69cc43acd4a7dd06db48c354c1c4b1431d69a1b55ee89688142245baf3425b88f0f693221ff0ac1272272417b00cd9ed69a300f5f7bf216dc6728865eaee008ee7813b28c75287a74b104cc6b8b7cc79451783d94c59038c61321b6f502b3d0ef71729cb4d54ea1c9e00000128000000902d8a00b5ccfcfb3a4fe9b255e32d5271b8509c43c65aa456e4f4f339cf7154d3fec1b33c295789586216369ff1f949018f880d539bceaa2c7dffe06a886a6aa98d441644292eb57624eaae712a9e30cc0f27bce54b31f47e72ccbb8065093379a245509991c1eca28e60a1bd80317f971964ca59e07bc005f19f438998fdf646aebc6d50fc9806afc8e5f53dd67eef1400000090e7c284f83939609ddc5034139cb7427f2749af0ceda579468f9f12f479d7635c42ae47924ba8d3ab720843b3965e8538bb4d3f5eec343185ab072852a202a1fcc6c29931b249290af29f909b1fd905772f21bc9db8b7e15704662ab924263420dac87f6596d3bc4e71a46a1cf88d4f130485fae93bc967dc32857b8e01d99ebebe50fd7fcb2dd92faa1fe760bd9b117900000128000000908d7ce67b739022c93cf68de7f4152edc7e66e6f3143d1a44eea1b64ec04df99a9d771b30c172a41107d84200910bad13432b7671508aa27af24c750e64002630619a0b65e54108c7cc30ddd12d069e940d114eb6ab90ee9be749a7bcb9d3295d5089b897b7293f24e7fb0973ad1f27cc180fd990f7821070841668a1c06d990c938af7a09aff5a53d7bf728d41bcfd7500000090dff4bf92d32b8b2e3a7371871e4f4d65727e6fb33ed9e2ea1e2422deefe49edf5ef2c295a6bf68ff112ef4e095753b60502bb42147723ec52452ab4a37d4f570ca86fc00d9502f948a5c5fa82eef730406dbc1727dc7284df5eb15541c0d030768979f802a46bbe2e7344d675e2e46431e7346c318f763c8dc24f4c50801e33ce39ff804cf65ce6a686e00d6ab5fb5a500000ce400000128000000907c05563341c4d959bb1ec9f9fc41d77f23142b298c4a1eed904d69a7157b0c3a50189d5c5955bf5d0435d27ac263bd4b211220165c7fafffa2bb9509b22fd06d3980a31d6dc535d8348a7fdb18111578097d8593f94d803409b86b58dde71104bd3db6805e1210826662237a8cd46b7a287d0da7441f6e16bca0c7cb632935fd5200946348a0a63b545772b8423e9b0e0000009029f26d7c01fa7cafab88f9c071037f4c37d2410658cdca53b9fd841e3edd61eefc8b447820c16b64dc580c87d2ee3bd86d980184853c62051086ade474138865436b54fcda93feb678ebb58693b3b14711b516c7b47b506e1e395cc1256b24e2c395e41c5a73a71bab2b04106a9984a50d8e80bf0a83ac05f25a327444f3db4d7475e579de9d471b09f10e483b1d2cc6000001280000009070eadeebee733c4c21a01360efc1e965a2e81f0178035b0b7ec4caa6679b944780d48c11ad55c38a024ebf4a0fae56e705f7a00b0add5e3a5cae06134d0b92771242fe98d4712a3a1c696734edfe95e62c60fcf93377e6e5090f9dd5566a389604e8d7dad82361b9f08688c78fcd524716b361cf210f134447905df5f58684aaf92d1f2fccd3faec8257844c590b155500000090c3a22867a8620f0e9cfffe28abac99b5449612bb6fd54c64303404077ff93221b0a6bbafb6dc1853121a38e8c41ceb201a4f72df30772822d0b0bf66fc5dd591fa7aab4dfd97eeefebf334097310658d0b1835b434bc3c7f4d3eba6051adbe7c0a56fbe6b7c99a3d6bb819b99b0646b710c09af243e9832dab652c0c777fb31c637aa7990452cedbbe5bf99fce564c1a00000128000000905cd7fd8043ebaf521a9cbd850967d37102d09f6578502cff586e78e552fb106abb60f660939c2a3a3425b9124b497d6e6da586baa74107df8af0dce982ce18eedaf56291a4578ee8d1fd147f90dcc8d60c0bfab51bafd8a24ec632ae09d3c9a69be585ce4e2ccae10be1fbd4a9fd76901e434cc1de5dc161de968aca244423a3a0d210d9d85c4518392b51aae13ff5bf00000090048a99423dd6dc09bc6ef055ccaaca0c591ad76d5dd5ee848580b5d183ea8d161b8ce35ca9dda3062b1919d347cfbc77c010a9a05a570f66bafac197419623b391d9cdad6621d9d9231537da704053b228d75d4f7f81682b8d581a30341a1bfd728965b622ff550008bcc73449d31f98098c20a8cb29424f1e69839742c2f17dbdf6a281d2f5fd28fd7182c77a9bed44000001280000009062a63d4cf8d7e88a831a4b2349f029df81f36572692d59e4a00a832fc78ac0c7d51aba71d7c5214c15806414e7c67b80fd6b87f0f5b7fdf255ec1794892d916eace9d91a8c6e4b0a90f009757b7261e8117d0f9c42a7e9b8b32ec9a46ec5fdd90e1ecd316dcda61c20e3c6eb9a8c850b15b0cdb0f70fef21bbef0ca1e514a28b1cb31871c75544235aecbf71a21c545900000090071d96e7f10252ddfef08711ab174fb56815d2886d3cb0ff770d8f271ecb28b52c7538cbe64f64a2062338df714fefb0dda0d2c3bd84bc961f7c78ca64e0dc0fc14aa1461a3cbf46c7a37970035fe98228c639c8b16c7b7a8fa6da42025581728142ca87773a67db46c28d7010a37be02948daaa6e9337189af4e0a7e16bb81c2476fa89bf00293017e757bfc1cb61310000012800000090305a5f090659bc284517b422b4073f2e32dc2ef731975ba67b96b4fcc6c952a52ec5cae273e7baf8885dd09d34cbc26a1ee3ea3498e3b5afe3f6e1aaa16bb544361a14f28cfae1a432e6b9ead74e18c12ef26791a8be4f0f7fd1959c0adaf46aa248fcf9c8cc776a54e188a4359fcb5d20faa413d68296ef1cb4ef274d42fd14aa5a92f37da51a0a6ed70ee12ab729df00000090f2395c0f619282673828c1636b1ea89a24302c610aa201824597322290193f759bdd5fba022e8545ca4e2edf05a40e97a5f41c18c06922a6a51dad573c0b7ee8c86cb0d290cbf2911e85a6813d7e11a20113f2dbceda944ff9308864ddbaa44d3f4c973e8ffb2feb80ff262a90773de82d90b97f239e92bbe51daa611577e7106038b7ceee0653fdfb71fe139effa92f0000012800000090f7312fc5ca7141f83996c597a01d9a0804913e7ef437b745189b553fe644b8ca9feeda938cb44eba925da1e7013fe33dee342cbe9e0b2788b7ae84ceaf235b71f94d9739b3227aea90a9d5405c0842d20c176184b55a38c7b0b8796ba90b07d1c6025fde1202f338cb3823898f23bdbb068c8dd7bb497a495e16ca21540e5f666d72f81f84943458256f1752121363cb00000090cd285bcaae2aaeac2d03b8c6956c3d34a00713d06965c991537134b6e893b5a3883390755fc103d92d3aa86c12f5b4442996d90dea03f021b806587046527c81b2e9f29e9187981dbacf20c462f6d9fb24ea5ae8a3060d7086221c3ab203624d5ffd1f0c5471d39d8abb1cf97db3faf30903520eadaabc77bd632031901e332f9f59eeb827ca7c2ac4cb3fff1cffea7400000128000000902fa51fbf4061a5c510008fc8f50dd7bea7e307c536d6ac7a1be04f63e350854dc001038d15c85f02046cb4ba99cddc1d0854f732c3bbd6c1a2ce3b9539b09ed75cc6799b3e3f7ea1906cb3e19b680978172d5e3a17d534611558b0974f27eeb80f11777d5c318b41e6844a205d90fd101e89e3a3ae05e2e9d335f38993d1ce40886900f317fefd077ba81368619d3f720000009082b1c27b7a64487bbf9d21871c878d04d6ea2d2a2a02373731e778750c81b8c89cd49b77f4af23ceae879f455029fcd1cf1dd56e1bee390dd3ec7c4e442c8a3607aebd50588621cae5b2e8e39b595f0c08a2a2f9fd73e7ce1bcdb28aaaa2a69bb3e85c20b58c861c3e158d4e106c785b0d65a543d817766a0496b91a90177b11a021181890c57d1bbbdc24f889cf1b62000001280000009001486e187b12186066c262477a0c9b4d03da45d3fd17af3487d985c03e46b03827b85622a2d8d00a1d8d2d07a84334cbf46c2ad6237afc95777824fa36a6049a568928d6a44f95f56ce61ea7457676b808c5acb1048ffa52e82ab9c059105deb84d041e13b132aa83142025293d9ee5607d19c7ca42e4ad037fffc86912010ca66386ef730cca4fabf41f7c6f5d13d3c00000090b7b2e46bd11fa912cbb171373688e4dbbbbe2b1b1ad04b37ceed2d53383919ecb1ec5690b91e1b30580453e59ba400bcdb76196d7c9d4927b00729e83ece424027a00e3276a93a61e84f520cc2f9b22209ad7cdd9fc875574302af75edc79983ec50596913c818961ad536298a310bc9183c3356971710818f06d0f260bd55d281087c8443058caaff394fd5a16a591000000128000000907a02b1a361c9e424797122d88f4883f61f09782cf351770c7d5577ad63d8291cca761a30d0a12cd1907a3c5f49470ee3839fc53d553db7bcf7978f5618007f4ea5c8ef5e230de4dd58a41c44a37fd9d129390c2ce362eb410da7ced607affbc53b841f31b58b6c0390d0dfa2b40e523817e47d9632e8e99d4a790f4f1476b47f63d6b90af6afe874347831f17e09820b00000090dfb3da723599fc52984084adc867d5b131624fb3a245e28097259b2ab9b5b60150fa80d7ff242fd0fdfda863778237e27d806cf7cae596e4f7c740689a7841b29c9a42d91eeeb3f3855d3da4d0d6694a1dcd9883ba8e205afe4e4712ef9113b129f648b6d3565fddee1d9202ef11d943145d3d6be489fd048d4626d2bc2ebc67ffdaf751ddb2cfa80f208aebf82aa3ad0000012800000090031c03dea41e91646208787581d5f4e1fb17302c08af4cd0668bc69dcfca307c928f6882dfaefa3f63793669c2168840617186da887e243c32a81d832a7070909d36021d76e58e001b74741e8cf37caa2662b915209192553f3a8171d57594d6bd4fcc3f41a8b27c16b7235ab08e317d1e953df7144645d59c657ccbe4b62ee8d64b3296548d7bbf1563093e87d7af1e00000090607f885db8abe4abde918c437fc0081506c5e8c1f25572fe375e43360c6c1013c597cb2b8a240d62864c00c17ef60005efb0fa59a155efb45fd62f17f862b53635ebe15728533820c500fd561abddf461d242081b026fb75401170bd90373cde8c5ba92a46caa46921dc6e6b71a91b2d2a94d77336cf9aeef2625fe24fd6e30a38a4ab63d1487c217fede88a5da38c17000001280000009086150a0013518186b565e0a6194b5ed3735e8fe2dbffffe3d4f7ed2281729dfa1a3334ecee8ddcebc91b11297ca7faa95d33f42e04e0e504e8f5fab8cd765a62ebd6e207658293914365809ec1497fd2298ad1cfc963aa5be4f2d86833961589ed49aea8df5f799a050918839cb1f4122978dce47fb40af8652e272155161c817cbb6278132d83265032d0f827c175ac00000090ee0452ea31f58cfbfe6862d55fb398794f3a199f3246b25dc4c8e4c61bfdab38f24e55749090130ada3eb60a284a88e294fa3b2e53890cc04849fb7588e10e3c3e4004c852db076c35de46c80a77260e1485f3e68ae14a08291158119ce92e1daeeadf640d5200b1b1db5c0ac2eb06632a83c101c86519295e058572e190e60275aa6a48d510ecdffae2095c6762300b00000ce400000128000000902c803df8807403369c656432cbdce60e1d926579bbba600313a8d722004e1ce464c3497551481be9f557671cffef62cf33348341244dcc7a00192f577d9f6fce776bd7b1529c625dcbdb80c61f2052e607086554e7057fb4303431adaaaf418167ff9fdd6d368d483713bae6a36f271e2bd77291619445eadf6363ef91ab37c95471f15b645264038c8b96b2dcfc8a3d00000090f59f02cfbb765e4a792754cc77ade007c2092e7130b95df0372803afbaf98ed2c5358375a5ee56e7f7e8bbc1dc7cb9243e8266c5361549fd869e956bd4618ed69c66bba2f1ce02f1ff77be776a59581d242876eafda24466264bdc6ac348b1ebe8d441181bde9aa6a534ffd7b446ec6c2bc6cfe5da9ff2c0e01153ad2f16611e830fb986e0aeb74c6c63d47c0c11410800000128000000905567fd5df02f911fca4e64532ef338fbc78f51e0711d133520c87a53dc004d5123b21333da8b8a92f0c02b4cefd1a3b74eedb56197983bfc0782c22d0595ae7bf6fbf909f6d240f412adab0e7330e5f1037eefb93404ec11e5ab0786b4c26da0150d51823dd51a5e9357febdad38f762240b1c7df5f5243248a7697e42b37fd714431b773d88fe2e7053976d4c773d1a00000090acbe7b8b2ff927a57e136525fdcdddd5fc9fec566fdf556f36fb87a2357035fb2e9f1c42a1ac92435a8cc14f17b73a87b1a0a3a6cabd1cb1fb4fc5190a6fe82113a0185071cd5f4c2e744e90ce435ae30ccdd0febe82f66fb54c36568b047519a96a18ebc54166ce442cfea254468de70c9513735ae8838bbc9cf0fe268d9f531bcafcb435e050a753a870466a16345900000128000000909dc9ccaaa169fe8f19996407f90983d83d1c6f297cb95066d7f8ec4313f5511cbc17ecbb4f0174606f923241ffdccb87467cdb5ea0c109e0425538e919ffcfc59591b30b2243bd8d04678a7bf7e5865a01b2ddcc608a28726322ecdfe1a3acf5c78844eb23207c21cc5694371725bcba053ec047b8790e19db88aafad5fa2849dfee7518644406873caa13ff0d0a855900000090348d0b1171214af22f5a822da37c072a2746c5884260dfcbc603c9ed223be74bede40529a01381808b1722f6d5b92f31a3dd0a8a89b2f25c32cac9a0e67e26c3f1566d52b1bbb081363eb3fc5bcd96872ab570861949126649e9d01ca995f837f673925eed0e23f70fcf0d1701b3875f143b10a44e6762968dcd217361d1466acb824d61175b08ca34d9a9374011d7d80000012800000090f48952a0956883a34c401a10c9f97ec53efae1c9ec4c7b5230c864ae0ca7c0fc218729bdbaf89b347614e766d51aa170680688118afe46c5cb2a817b4f1cdcb412e598765d460463398d286e893ba96527fa6cc20569bc654a8cf1e76df5e41520450f3e9646674910a7cc5f2f6ad6cb07b03a6ed5e7670e4494fb13f7d5a75e72cd728d0363d7aa08b7761abef4b3da00000090db2897a0437ec2ba9f366e88ece23670290ff06e269eaafc1eecb43b41aa7f53a96fa2933f28022938dc4d4d7e397844e4a9bcd7f79968ab01e05277e7f8d820aed271e6198e5ee96f6a70bb0c1cbdb929a9c306aeab9c7afbfe3b2c9558798659aef641daefc0a1801b4aa613faba162dc55de1173652dea99a971823c29032661767bd75f24dc53aaf995f98cdc6890000012800000090c7a4aca8720eb3649eac8eb7419ecae0725206544f9f14c135f867014c33595ab494a94226c3fba20a3b6dd078cec20d7032c0478533261815d5c6f34c7490910af1acbf60dfa203a974b3526e0d6f170853c20b3dd2891391e32c4e5e6dae96aae97bf3a0c483a33d2bfed18b518dd60a43da0389df5659213258d86506493a11c476c6173346943409877f3f1eb8280000009044cd6d5591321c78d3ad1ae1bf3920701d1cc0c6a73b5b5d9034c05466de6a3b7c9dcfa0bbca612a895d7a418e1b1513413160f9e6a343415f57b3e9cc3865c966586d3b70c285048326cfd317ee6b9f250307f80b904bbcaae1cf998bab4d7e0c3c9d6067e16993e186577841c0bcc42a7732ed26e008b9e9a8ec5db481cb59cf3533dfc6200ef3ebf40a40c4dff644000001280000009005acab802e3f5f7d14a97db5dc83caa849d21005335eb64ee3f7d7890913e47c41935942c6492765d1683f3e58618210b938eadbca1972fb3ca6f933e13eb53cc28a8cd4bb551016e8e6da5f43bbe527212154a463316eeafe582bae589ec21dc4a3f04ce8be15fa7574cc8f85297a7519d803802bb93115202731de6c949bfdc7b897c2c20e55699a45b639e74197f700000090db8755368a5883f4c8fe4f1bab8967d086a2c03cddbe926a6b89d2193ef0e497f2082b9a924618d54e483ea64081ae51a51c10602447801112189d25e238ca3f40e2c1b0fd34aca316716b7bd3294e4413457e9893aa9397a1d8ef44dd4fce4e51426d55377084185406aa294c6c05e82202efcb16b1d3d895622c79efaf7de68f35c641bc19758cf04bff359e492efd000001280000009087ac7014e5e07bff87399657ee1763c71b8999148890bec2db8c429b1f90bbd42d17eb24235c38a58e5fc5731d4817ac467a3cc83c85940cabee34021c15207429514ff47a00c8b2064f38ed9513daa827655841b9ec89ae70fd3322615750c4e254c912b65a0e47da5e9d887dd6066c14c97dd4139a5e24272d10c6c8af9e008326ffc35057b8e61b56b89dd7026c48000000908f003eda2f032f79d6daa0afae9e777d8395e8b99a14c184826924c613f2c2cfd771420c41e34335484310ae29eb2f42354ce93093db217cd73f1ad1d7c82751c9840f009bf99fae72f6499e5aabe4e7303b2e67e46729ccb482876659117e12fbea701f7f693c686690f16037629e3f2e4afd1cd9ba7c7792e0f75312d43121d679cb3700ba52bb99bf7163175f39340000012800000090fcb668f4eee987dcf91f02506c4e276cbda61f718d249c1b146908ae48773bf119357acb0d33d981d04fa30e254b74786b8af9d6231aed0d2ab609a427aa1cd7269d05a908be3edff62849db15916753094633d30c8e1e1824d63a471510520a61500be387faced8d8f2397897a79b9100b2c3749f0cdb1b89a4635ac91966fef5328f7a51d75f6a64c5cf262929d0ea00000090e1fd1913250e3383ece01108e3676dbf45b6af7cd54328a1a6a9e032b3acd5c84c7330714433f147691a15dde1097a246a54c59aac1547f291930e5fd3994c71eea3b96288c1c2444609b675711a615608fedc92c08b028e141a647c4c6240e10e01a1b517bc9b1fbfffedeaaa84939d108fb5b48bcce4a6403fb3a6297a864177d35ec2f56b2f41c1a5c18fa77c78000000012800000090246b9ef39b4c1f688e2a9bd94cd7886aba49dd6c2d7a994a55b3b210fa54d50b1d94c7314b1dd66727a04194461377f021887f0bf08d7132952ac4fefb34a22382487b2819ff3f689c191ec33cd639fc0354c3c1f82acb0665b97f78cf4d7ea6edbc09645d6fc091fbdda38ab51d614206ed1eb6712031a70239dba48af173cc72ce5c8dbd4b2f2ead260eaf139fc76c00000090c47bca9d4280b30fdd30ff309d250754b715513d9b7d45b38690e683cb07c2aaaeb63b0f0400b0116a77e295240d94e39c7682a0f1ec9e1396aafcb5ba80053a5ffb4cdc262aee196781d2c3c92e5ec31abe900aae102106925359f393e17163def75522a8363506ff77b008dfb3598f15cd1ad0f1cd2c9940d6e35a85fa4aff06b2fca127af77cf85b7ecf2134c127200000128000000901efcd448119223b36296649ae27271c8ce44425c2257bb3b4d322767bbcc93df4e3405b9d57b89cf3a321725617ccd1718e3c2b485bb72e40a5b661e7c6674522447171d2d600265fd1068307f5eddbc031b050c27fc1f6035e51fc86890af02b773a7bf6a2b79151cdefe58e55c368405fbc782501d3ec15e509d762b578fee3711ec85afcbe3ca31714291ff4e84210000009020105be65d60c582c38af508ff84d115ba0be30df8b55ba5b2644bbb15c4dc9dfb46399a7bedc1e12e57530f8d2fdba47e9f59062a9384c5eb496795964f33e222a91ee413495921cd45f18ec0bef4a013d91373d3e7c6b40cb9eab782d295c6bfc1fefe73de88e8ae380363827204bb2fd4f44899b714ae567340e9d2b75ce56290389379b01521fc01b1ca40fd7eb40000012800000090221861a7da93d0ea2098a2dfd72369f097f2390e73e14b94284bddb6aa412027cd015bd818e966516ad0808b28e95ba99b04271cd979480ba3a70513df67c7d10adbbebf39059d48bd90d70fad88a11b15a453727995b3da07902ea4ec062384240e406e45222bc6fd8b85c2a97bf1d2282e381e70d50ed6a430be46b27ae56fde68dfc666c7301c37cb7109283cdee60000009020e262f5717b624c3dc1b984830aeb3377f9952d1efcd31851ea323cd10d6502da352474fbb82c370582a685612f768d4591761d67d3923c697222229eb6e39aa40e9103d896d9085969a6e250ac170826e9d5dd40287b9c06c538743a402ed9c7d4c84429afa70fc4a308caa453ce4919a295d209efe58669e9f8b23280e245ee5c5295c434be404440831f44d4bd63", - "calldataHash": "0x484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c1258286", + "archive": "0x0dd1272ee1ed846392f68a239f16091869ed0a82d4bc8c4d73cfe55bd61049a0", + "body": "0x000001000000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f0000000000000000000000000000000000000000000000000000000000000270000000000000000000000000000000000000000000000000000000000000027100000000000000000000000000000000000000000000000000000000000002720000000000000000000000000000000000000000000000000000000000000273000000000000000000000000000000000000000000000000000000000000027400000000000000000000000000000000000000000000000000000000000002750000000000000000000000000000000000000000000000000000000000000276000000000000000000000000000000000000000000000000000000000000027700000000000000000000000000000000000000000000000000000000000002780000000000000000000000000000000000000000000000000000000000000279000000000000000000000000000000000000000000000000000000000000027a000000000000000000000000000000000000000000000000000000000000027b000000000000000000000000000000000000000000000000000000000000027c000000000000000000000000000000000000000000000000000000000000027d000000000000000000000000000000000000000000000000000000000000027e000000000000000000000000000000000000000000000000000000000000027f0000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b700000000000000000000000000000000000000000000000000000000000002b800000000000000000000000000000000000000000000000000000000000002b900000000000000000000000000000000000000000000000000000000000002ba00000000000000000000000000000000000000000000000000000000000002bb00000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bd00000000000000000000000000000000000000000000000000000000000002be00000000000000000000000000000000000000000000000000000000000002bf00000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f700000000000000000000000000000000000000000000000000000000000002f800000000000000000000000000000000000000000000000000000000000002f900000000000000000000000000000000000000000000000000000000000002fa00000000000000000000000000000000000000000000000000000000000002fb00000000000000000000000000000000000000000000000000000000000002fc00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000002ff0000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f0000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000033100000000000000000000000000000000000000000000000000000000000003320000000000000000000000000000000000000000000000000000000000000333000000000000000000000000000000000000000000000000000000000000033400000000000000000000000000000000000000000000000000000000000003350000000000000000000000000000000000000000000000000000000000000336000000000000000000000000000000000000000000000000000000000000033700000000000000000000000000000000000000000000000000000000000003380000000000000000000000000000000000000000000000000000000000000339000000000000000000000000000000000000000000000000000000000000033a000000000000000000000000000000000000000000000000000000000000033b000000000000000000000000000000000000000000000000000000000000033c000000000000000000000000000000000000000000000000000000000000033d000000000000000000000000000000000000000000000000000000000000033e000000000000000000000000000000000000000000000000000000000000033f000001000000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f0000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000037100000000000000000000000000000000000000000000000000000000000003720000000000000000000000000000000000000000000000000000000000000373000000000000000000000000000000000000000000000000000000000000037400000000000000000000000000000000000000000000000000000000000003750000000000000000000000000000000000000000000000000000000000000376000000000000000000000000000000000000000000000000000000000000037700000000000000000000000000000000000000000000000000000000000003780000000000000000000000000000000000000000000000000000000000000379000000000000000000000000000000000000000000000000000000000000037a000000000000000000000000000000000000000000000000000000000000037b000000000000000000000000000000000000000000000000000000000000037c000000000000000000000000000000000000000000000000000000000000037d000000000000000000000000000000000000000000000000000000000000037e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b600000000000000000000000000000000000000000000000000000000000003b700000000000000000000000000000000000000000000000000000000000003b800000000000000000000000000000000000000000000000000000000000003b900000000000000000000000000000000000000000000000000000000000003ba00000000000000000000000000000000000000000000000000000000000003bb00000000000000000000000000000000000000000000000000000000000003bc00000000000000000000000000000000000000000000000000000000000003bd00000000000000000000000000000000000000000000000000000000000003be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f600000000000000000000000000000000000000000000000000000000000003f700000000000000000000000000000000000000000000000000000000000003f800000000000000000000000000000000000000000000000000000000000003f900000000000000000000000000000000000000000000000000000000000003fa00000000000000000000000000000000000000000000000000000000000003fb00000000000000000000000000000000000000000000000000000000000003fc00000000000000000000000000000000000000000000000000000000000003fd00000000000000000000000000000000000000000000000000000000000003fe00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f0000000000000000000000000000000000000000000000000000000000000430000000000000000000000000000000000000000000000000000000000000043100000000000000000000000000000000000000000000000000000000000004320000000000000000000000000000000000000000000000000000000000000433000000000000000000000000000000000000000000000000000000000000043400000000000000000000000000000000000000000000000000000000000004350000000000000000000000000000000000000000000000000000000000000436000000000000000000000000000000000000000000000000000000000000043700000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000439000000000000000000000000000000000000000000000000000000000000043a000000000000000000000000000000000000000000000000000000000000043b000000000000000000000000000000000000000000000000000000000000043c000000000000000000000000000000000000000000000000000000000000043d000000000000000000000000000000000000000000000000000000000000043e0000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006590000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f000000000000000000000000000000000000000000000000000000000000069900000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d90000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f000000000000000000000000000000000000000000000000000000000000071900000008000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000004410000000000000000000000000000000000000000000000000000000000000480000000000000000000000000000000000000000000000000000000000000048100000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c100000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501000000042ea6fe02855d8c72905f35f08604467117c037962e324c9a793505138558b3700c94efd9afe573212f9bf596ca3a4b42ae57f59e670a7cb5b9440c54bd8ea2961856bc4892b0b3f156ed2aa87463c389bfce0fd675a37cec77ae5d753fcf593c12f9d3f397c2edc9e4a6a5e485641163525ca802e3bd93994af997a9b9a44f98000000000000000000000000000000000000000000000000000000000000114041414141414141414141414141414141414141410000000000000000000000000000000000000000000000000000000000001180818181818181818181818181818181818181818100000000000000000000000000000000000000000000000000000000000011c0c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1c1000000000000000000000000000000000000000000000000000000000000120001010101010101010101010101010101010101010000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd0000381000000e00000001bc00000090763d50695e296c417e7fd7bd6cf35a97ed1c708eefc8aaa1eda67ab2228b0bb6025789d764664b14c7d42eb0319d854194cdbee51deb0563354060f57f1d6336a2287923e302267e448421bd61859645152c7c6279530f5590f906e48b214958cad0a6bf18d1dec692ffa633f0e15c7427b5b507673696541e6c11d47bc47ef1a690a955eb66c105f410816d0d4995310000009044fb92123e56ad325099bb495bebf9220fec34b76972b7e5c425ac8cf8e911c6b8c4fb114e2cbb7981772f08c4d3335c3a0d7b763ea5c862dc37c78be7aa73207e8cf37bd2beb95c1843df17fd9e166d01e3f5972023917febe7d45797e3467dab35174b74e9072f8e3327814e2462131668658ccd3cab395ae6a7329333afdcfa15ce428718b15e1d0828392dd3d1650000009048e647e2915e58393481cdb94298db3677d4a86451a6f1985d75ea4188018e1a1999da6ca5cb24184bbe203348b5f4bfeeb2814238522b1b342dfaf799754f3663fa2321057091d38e76dc91afb3888123cb25f01090bfaf75e0f66095472286307669ebd902e0ef21563b89fea6129f24c1fa29776d82b8a75f01e793e61f8f994e0fb88e6f235ad2ad23c0450d4d99000001bc0000009074c50abc096a04c33ef18260b70b4fe0bc416903654b57a846c863aff5900df9af981e747c227c6321971bf4b04e34d75206ef71f7e4bcb9e7c995db9217da78f4614b2019394a49430c4670bb80a5690eee7f95aca6ed7bd9089f6e1af6a6b602056ca4ec01ebc815db4d1cf3e7334816ca76ede99ad9537b38c464926ad6a444390c99f6365d4384c68c9c49a3ef3e00000090d8e6a5ff78b39975f9b787c3898073a5d5b467aa880690bc258ea8d01aa7e0e314753d30bb24b1428e651f7813a9d43e94be79addbe33c515b70f93d59729e5db8d839aa35fb47bf7a2eb43acac8e96021e4360608a938dd512d2af37132ff4bb836382a131c7faf79334db4a493840f0d1911c9e2ce77e80185cae63e22322ff557b3856d41c9836cb3bc49c030d9b00000009043a97d2138947f8b624baadc0d70adfc36f0074a2bba147929022ed08e419354626d1905f77ed8863474a11487677c71de53e3825d352c949f5ad0fc3c7c6405b4475f7130ce5cda31d60070d5f8a5701fb110fe1f02a7999d7bd7e891becdedbdbd55740403a060f260383e564905bc1d76ee41ad7a3636b6a317dee3383353cf3ecbb391ff997ac57e2723c838d227000001bc00000090a1eda4b31f5dbdc7d490f6adb65f37af25912d9bacd84e2cf08123d1516c1e7cdeaa783bcf70cf6cb81085b55e1d3fa3a79f312230284e3a3aebdb6c524d760de89b78d577116dcb4619642634e6484f27ae1f3bb36b21124d715234d0d30539486f4b31a1629b681fb566224a9724e21b2a7c8ee676cf5ae59fd39a4e880ae9505b80d2ce4f52337df36f0da1a557ce00000090d84345024f840c9deae3eb2512996076edc7b67e8e999b837abfe0cba5bfdb2c8d3e649bae2b374a7f59ba0c4c9a30d3f3de2690c76e931c2826b6d00a77ae36f8d617610cf9577a14a78a24e3370b8e0f50e469dbb82a50dbab7e405320d9a4938850b2384b32fa00420a5a87c8db2b20f958bf653773c16b7aa50cd6aa62ce1e673c46b251aaf725bc8130ea7dc7cf000000903d439668457140675a615d948392c621295b37712cd411763918e820321d014f9301fca09b9ec926feed5aa39498ed2f0ec949794488fc3f0aa5f1abf41567e823c02b4d7c1606c03604672e0a3304620d50ebb0806fb724f8ba63221747225ebd6471a2e945297714a61fca26ba4116017e40f0db29a18996b258be5a619e920f0f4b1b793f9a143551d9ad057e2487000001bc00000090ba197708a8430e941d6fc334823136c5d78f07317c64b919ec51902d22140f5d77b76bca8c5eef5de25df8ac826d3a18c7bc43ff1e897163a34d561540edbe97748f8a1c5902e02d95c492bdc6d3f60a072ab6d2071e376a281da7db68438c9ac8b45e61d02ce39141bc2c79cbbb1a6b07aa51e94edecde313e3474fbc65046df06620ccb2304a80acee864837f871340000009099ac3bd891b57979c5687b217223ecf32685cf0cd003710ac8bf4ebc88037b776a7d5ab2d0281cdc6ac859d1d0560428f8682a8e403e02f0c2bbe8d53b41cbe28bb5f3218376588769b0d2de4d1aad3b29d161c362da86ef6f3ca92a2afaa20097dde8a136704acc7380b72943d491060ebd503953b3d1b64692638e63240a5f712f2233722c608d3c38516fb64cb802000000906b142088a1cb930048cab2bd11032414af2b0a5cbe0e44290cdf2f4e0b714b3fbfa636e7ebfb880fc4d23d700115a4fdfb97dd5d6fcb3f2adb7a356f81d61065c579196a26e26db6274859656ed8acd70f05b208f5ee7712feb240bb3d4ccab50901dac74ba9409741d69accd55f56801371fb09728d8551d83c2a0cb726a80a77f4762038d65a56eef9b5d26cded3e1000001bc000000909e1e346175e0ba4104d7ef04d02ddaaf31817c6d63abe809bf94023e79a0b4908206c7f663044f3c8766a7b36b2851ef747711ff208bd6e5ea909f3612454149bede0f33a7c3943c023621f9dfb248831b13ec114d25adb818aae0b5f4b07409d2266578513262909a85d9ee780fd231131f7190eaa1a62d0ba9809c20c60b73e11683ef8c057aa86230490ffe72c22e00000090a57f8e248345363587d16eb57dba9a0ff778ad28fa0fdf6753409955e99ea2a4fbc30af5a961b74a7fd676dc6c14b6e5d4d16726f82c2d896253373c312d2fb99dca327fe959db1371b4832de1596591142e090599a78535ed2ad9efa32830c806ee871582b1e9d4a6314367aa0848a90279582932c58afbcc70cf7c844aafe01cee7787e4cca3244c99f9fb214adc4000000090e70521e850fc0fa00f700acfa53526c18e8ac1bd823fcc67819bb43a4c0727155287dfa63ddeedfa4e45a321707168b9853001d03d418fdc099d78c313d9130fed5e5267dcf19d424b5b33fd910da37a0cbb73aa4538b883f92e2c79ce0f68230b5c43e5c2bc4a3b97064f57bcc467300039f0eb1b9f860a8a6cdd0b95c37651cee8c8e94772664de4a3ff2a889a029f000001bc000000902f60c46c672de108b2bfb94dd48eb2d446d51ed71f51ac32f8324f464c8c9d74a4cfacd8c264e7d815d47d412a034d8669c23c185a4e2e47bc785d5b96476d24efbbb945c5ea287dd135562768234bcf300a3dd5e0f92884ff0fb194903f449b738639e232e4ed3cd5098fe883ada9b4215bf8b600006131f0b8d80d60e449a50336a4597a841e94f1d9e3602af980f7000000903d6ba074fc2f9cac04fdcad76b25443abd2cc75182b277d01b134cd5f62d2e1a4bcea7faecb667c40b72ce6d4b03a07fa828040bc7f397933f42a4edc3ac37fd2a1754481f95e5219480c7a060923ad11dc720a6ef999568615ba8b6465d275f83229f738110cf12f9ffdeac538694c8301f7bdbf2bf08f5d7618f580d745bbb0db93c6e26842ed4fd329f2f45e49cd200000090c4675df001b04b6722c98c8f0b71a6a871410d8eea06d9dfc5fd25ee14a9a2db910e8e459909f0e07f104fd0ef81587f6da7a39580f673ce0fcb597650dff615040dd90ae9394918dc25e7b6e9f3194f12e2702727f54a9742703232baf98c6ea5a00260a0c2c83bf24c353c1bea2caf240d56d18b1d6183c3e008c0ca266ff63ea5bc24b521fde209dcc3d57defae79000001bc00000090dd6fae0197b221d9c23f83e20d52ca769588924cf4653a351ace27fbc854cfd4665143f2fda8b2d8568ea21490f3e3c830f1f4a0c17eb3f7193d24785472a986fd507b3eb1fe7b12867071a3866704ed16b07a4e4392502310a4024f70b5450fa4693976b96221f750d0f5e6854db70801217ef19948f21763e933bb02ca129d4ed61ff2e7cf57d390d0604a0db181460000009071d1cc239cd677ba31a331d98980b15330662f194209efc80ab996fbdd86dcfd4de8f82a9044d706ff24ff7c58b0066d6d80d1eab3a7d293ebe28c84afb6e35521d25b37cc7507fefbda4ac5f5f40ee912702e69a02f2b5f9e8ae58934896636e90bf39bb26a3ba30c7d0cd97ddf10a71dabdde2997f3541303610d6f880f9427bd0018b682bc2db24d7ee76f4dbf04800000090426b92420322bc520f6011901ec3df631dccc4c935784d353f1f749d4579aef2b1dbdb222b5774d7c133c8bf75abaa704cec8a52cfd8a51c3e173dcf20d9399e31a39c32e8ee9ce528e3a99852b31f330660ea8007d64c83b010806068d417fb794dafbe802fe2a723b92ed7540c6a28222ce102a7829b72854ada78da595c3aa8d561c37e8eb1faecad2a924665ac78000001bc00000090f01c43e42a166dec160ea8dc2db69e783bb40309a56c0f8af717b7428b6d4ebd1808d4fe6dfd09aa0559671180473c9431c7959bd542a3fd6b6fb3976843ee5a6a7782dcd4c2e8f66ae22f4fb0f0106924a9e2601bde6a63c0e30bbc24a8bde969177ef97b73256261369b9722f355980603910bbbc02ade9ebcd9e6200a35e40cf4fbad8976bfb0260c604cdc87921800000090ff22e481f51f0efc4832bbfd52a93d87933faa5e34278f0812301c07ab0a5fdffaeab49256d615d0230025f9ef2a293cbd9fa13d5ff1048735f911af3a8611bc69e352a6255ed8f57974a78f9bcb81ec08a8ddfb42a2ddfca1f5ddfd4dddd5fc1156b603cef903afdb2cd262ec7bad3f258bc1e2317227b132414e55ab299b11acd98f45cccbc769832a6cc7586c903c00000090cfc8b9d4ce1a042a79c0e01cda17fe0b128d1725f40260107a49da748b391b4b34c36413f001b4e8837a8a34ce2a678c822611014a39a6e5814708f6b1a5b55d7867c4f914b0976fe7e531a5ebcc2e481dab21d620393af6ea11162207b0bf08bcfa1bacfeca15f17440a5d0021341c429bc28a183c7be042dfe6fb245cbed15fea5f56d93236706f1cc68b090ca02f500000e00000001bc000000900bfafc78763bd2a8f902a0d60eb0e378333f28de1b91568c13810c252bacde67a1556d0bc493cfb86b31b73aac7c1cb441ff7b160fc65e368a4253d561321010100a8b168806978d6d6f964902711e89094eebf594cced9ad6e5596f9c0b4cf2393517517666a3a37f8152fa41fe6f2c2fe4e146dab6f660828bace0b4fa4552abcfbf98c4bac67b67729364a8eb22510000009040a490560cacc094f2ecbc9c41ee17a6eb726bb404aba77c47b24a94e55a178f802774a37f6d755a239167b9dc772177e09619e152acc1edf62dfd99b9c9c2ef59de018e0757fb3fd26366647c85ce6e0e4778efc3d7f67e0a3a4d1eb9cb7d70c51e3173b4d4ad55f95eba265001921d0521475c14403376403c31690c756da4f8056555ed007b0cb1a599d1ecaa074300000090f221a293e28b099c0a3b308fb73e367aff92d41421eccc00cec77b66015fe0a793333e90d54954ac451f648dc1e85bb4e6fcc787bd7aae5b6cc08f3e7a25576373bf6317efa211d4460be2d9c20933a41a22a03a72a23d5d216ced7447a874bcdff8ce0bcced3c402c7c89894b6f2499115ef06e48712bcbc32e30a008f9faa45533595e8a9d95c6ac49c77b2ef08059000001bc000000908a23ac574583e150f9b8112e17c080a32ce3a87fd737b8adffcc7486b1f2436e58d74c0d4f2534f9e8bd2d297aa0067a36e8ebc1fb4b8294525e97ab4b148e23adab5c0f48101e38cf3dceaddd8f2a380e85c85a632a3243a4fc4d9f046788232f668f3c2c919641ba238fefe1e9597a2a1cce9bda441298ce6207b321592c2c85adb8a009e4562ee14f4c6ff0c6b4a8000000905aa5ed698bb707982b0a3da5b5a8eb24178599c26043bc2b87ca5978264a49f5dac911abc7e78f05c7f99c8f124661d334467938bcbab875c4fc1142feaef450b81b60e5ccb4ba006573e57095aede14035fce412301c18ce231870cd5a6919329dca9dd959091490032b98b074242910ec68df86c4c2d1ed8cdbb2272dbbff13b78555db8a574651e08f1c66e7238fd0000009036c84b56b7dd028cb0fe48ea83c27e511d07ddf50d49322b8d5a1a68ef76326d4bd00d36189bb48dbea8a16a88d7cfc14a22523490c581d50610632f447f4e5962372a4e1a4ad24fa7dfe72c3183756e0dfdd3015da3bd5aefb2e688d8c50f804d0144ffc6ba05889a462607f3c16bda1e19daf0beefde473e16205694deb54e889134ad30f21acec6e6898dfb1ed820000001bc00000090fa99627d94a5d06efd1ee7489a61f01e2f3aaac340c07ed059469c1821d9041c972e02c1700d8d18b0191a7d87794b2da4ea2783ac6e318f2241af9ab57fae342e930b55d1b77d470d0b049a6ea47c5a151f6096b09c4ec8da6ba3fce1c73e2728c685ff6f185b43b6f3465ade0a34d319a2ea8f61dd9e9ce733056dedd30229e807aac3040340a497c93eca3052434a000000900769e4b0ac448fa876790db9e379a711d65db6771de98fec4d961106ab327573703a65a8db1598c5d39f87daee34e6d6b72eb5f6739e5106cf1f114d5aafa87a6b0b113139051695eda21ae94c0bc0941b86323f953272774fa6f40affe14173e832d7e0059da92dcc7f5372c1d8e7811afafec9b1ca1cbbbfc140fab62c3d400bf69c279cb32aefddea52dae4a982b20000009088307aaf1a93dd6300e0ee7e2d2d9d5001646944421e6d265abb6e9f19d488114a89096ad40bd95b2e0de01271d3651b34a751a821a92020dc942c32a03362f9eafaf70da45a4aea4e5b6d1b2ae6abbe0688e326b7fa26bb49e3b3ac51d1da99f3f92fe96d304e03230cc8a21e03913a0da00ed9e36ed447a5b38a6a1921822f8ba23ad116d69b387dcc9af1add3847b000001bc000000905dc09b50a3c2dcab81aaa93cb23aedea31caf6d350416910f921185580cfd22f735673aaea2881d8fb931f0d772ee589383d79c82419df81529e1395ead7f98dce13cdabad35945fa27f2e060e5dac0a0a2bbe9cca07639260e1d614af08f268384c55c71e59c764f2666205926f150e2402ad6b4f736f37699bbd8b691f1aff60401347adfe84d406cbb32ebcbcb6200000009016fe91f3ed58bd25fef5b4c03adea05da87faa50fa8588fb888da09127ee6d840e04f7fcfa77fa5a4d440ae0245108aaa366e29115781974a259a73d21652c7c15ecbd7867268ed8a569767d09b7e4f406a69eb1773a067f262d64abd856d357ea4cd76eb3efd8c94213309355b26b5b275aa54488a85bfa8273a73d39416f77c7b00de54f9d852bb32ef2455cbf3388000000902119a8c1a1e6b28efdd96b2b5fbc04e52d4f2668d14ee7b6cc81666fcb09342a0882e4427465384530e472833f0a5915b05b56cbdfdb0a2220f41b78508e85ab588d38e3d60c8f1948ab3b304989821b105c627ec62bc99223bde0d762cd9190e79036906cbdd4a7abf361fa91c506042deb4ed5d6df6158ff658370499e2d7bf3e7a2d464b1c0b47243274656fa5eb4000001bc000000905ea0e7632d388358eb5741c3f11f29920d98612924941aab993e5096f8ae869c1ed474efdb5ecc21fcd6fba2b47a68eaf580fb2a845ab483f9872f5ebe05ec0c186ece38867579693d3663e97665f1c907fadcc49b56041bdd358b38b9533ac08faa9c5071c32eee487b9b36928afef72ad3cc3179fa8cf6cab2d77933343d974cde39653b0fc09736f242cf314f85c000000090ae07f491119611c7e3622fcfaa0588693a6ecc5952c396e3284ac9baa9488bf0492a4d9a88d48edce36c21c19afe2fe59331012c59a25347d847066fd7e4cdcbe337575c40189dc2d795c302ee8bc03821a9489ae8b0d23e8253b42fcb2983fdbd5e0f5e56c7d5caff8ceb292ecee9a91fc78414869981f5616e1b240ab637ef6091f19e53aa025d1d4acae2fadf2d340000009073a88bb8d03ab5e51cad71edd9e2255c5fa2a3c49eb88f011ac59a0ee1ab49b3742febbf476bc9fe81cf33a028ce9cdd920ff0c23e648efa9841a3d196463d73b1117b5ad38a813ed78e5f814cbeec580f87df878c2934a571cf207e83a90b15cacac1d5026c979a392fec601056d5960e4fff47533af34f45361cb424e20b89cff5f10a8b88c684b32b226936290cf8000001bc000000901557bbc9bd0249e9cf9737ee312c3ef00917e84808dcea51fbd874bfa5ee6d0dc8bec75ad8a46e5a4fe45fc30ff2824420cb32e23c9388791f211bbbd841475fb3dac3f9e21ca4e8d0227746ed299e14212163716215ad400c0fabff0e933605c76a770820a7c13712ba4a43900a7c2000123cde32f0c07be5525fd7b94b5c23919d0078213b52b1a267890edc2a19200000009092ffdccc79cae5fe9feb40789ede8c0a9789b0a0820e62305607e4a7cddff8d721e73747e7e86473f8ba61f51178a45d8a74dfede66a5c1595ee647ae7199beb98db6d947218636ac37e0658d00f6eb008a5ac9fcf97ffd6b98039ac47038f8ca7ced9d35adede2649da16b207f0fafd29ab94c4cd8e9caa2835673254a58cd97d276245829379f63c1235da64f6584c000000908c1747c37cea18f4bbc1c87e5b7e3566a9aaa31dcdf4eba7e12c93709f6be785e978a2ca75d64436f1062df234d1e3b233f3efd46175f8c0cfbc790fe3028017b1fc84400a82ea5e00946829328ca5c91be7aa3f24d9deca33d405c57a4efe58256b031c9176e3f5d8aba6e71b31500d1dbf7fcc2f8f5d95b3d4e8c6b83c6b8528e0c5c1a658870fee822539e53c2dee000001bc00000090dfe7b85078f4fcedffaef62e4ae8bf7c221af1fde439e6b81fedd1869bfe7382f8c0b40bf527f697a86f50a04762625a15f2ff4c0be720f3c9a199dd06b946b7302aa6efd2795908cf941a4fdb125dac300cb43ccd3076c073c1b4063e778395656ee95cb22974265fa31d2afa20727f1f0e9133c4536e905c0677c2c7cbfea8611b26b14874299508a432dfd11e644500000090cbf58b5c2ef4162cceed53b21c63876f76213c416ac9b020a09d3ca993f436bc522bf1b3adfd0a0c444f40f5cc00cf5aea2596704fd66ac1b4e2826a494f8db7360175d9e52abbb1bfc66910769bc5d72c67d582d612c27a322db2eab7c531e248e0c18850f85cdfbd295b41fae387c224f89f1bad0eaf8b6b27343057b854a380a54773ac0c6717f8c9bf1d869b4d030000009058ae3b96035fa7521c1433aeec1fbd6b744e6e7a7e67572be908b6ed420f7edc02df40318493fc2593f5596d15b700e4fb2bcadcf37348ee696896ee9b2816497ebf32e3e494bfdafc03a58fd39b39780ab79f545030d4c678efdde173f6e6ba467b0202158b297df15f2d00ada1e9c30b6038be376960677491f0afcbef90e2f3b984bdeacb54871e6a59babff6c031000001bc0000009088119de326bb7d8c037e565e344a50c4a60db5ee2e8ec9710fa6cbaa6adc03534cba0bca180cb3714cd79959055debde0027c7d5f5c26ba5d4b99ebf2a73876e20eb62e37ca1e58986b618af3670cc612f018869055163832bbfed4f5f3bfcbcb386e7d2b9fd08188991d9bee09ecd8e18a4bdd16c0c409f2b08bfdbd1b0031edb27aa0e2efa56850cf19b2f53118142000000909cf0e84e6125fc0c0db99ebf50354f52ecb93d3596b239d2aa08de8ca9eba3cb9ec2b406c74d05b55aaee882c9b1a5dc6b60d2a12b617b3571972c29600b6dfbfa800392da80a175890c65909496dbde1f95734fe70daa65601d380b8ce7417606cc0a36b4faece4d228522ac4c53127213535b6ebad2b38b83adab9ed3fe3ad6d07b8cf105cb26efd9ab6b07a5c53d700000090e6f14e47548dac22b102a5cd8291220e9ce398773878f3e65a9fd80abdbf77ae337353c5d93492651e67ca6bc325616b7af2bd8a8f5b8160b3bafeb6728b2549867f2a71d62d0a3a393ae887035ab9d51d7268f69310baa2a8bd9262ce6f7f751bd63f916e553b409e3ab77d671587a80db81c189cbc1f2696ff8f40fea8411ceb142e7f40c090e1553cf3ec3f9ddce700000e00000001bc00000090df1f25b4df5205023034c076464967c815526d2c301527f07cfeaab7535b9cfd601f09c8d0ab90eb5cebc4c33bb1e3f92341c395bf6d7d05002738c562f721d09720533594baf1cd4a31e1aba4c4d82803f1e601fbc042266f5700ec96da8a44485d9f00bd0b08db95a46afbbdc379b41eb94ca103e2dfbf9fbaa94260614a9771c9df3372f93d025afa43d0b2fa833700000090c157d4d7bf3fd500cc77cf617905220cbd0e0d368d7179fd04ce5fbfe725e94929709f9aeacd9e9dc63dadb4fd6425399cb3b1cf03f27688271db4fbf531954f31f5048d8154e56a8da108735b136ae01a434bafff9163f9c3bafa8fe1a3f5d135dcd6ac7db20a9bf417130bd1eda5652409af9464fa831afc5e114a1ce0ded66ffe7ba0a328472dd4dae2f5ff500417000000908174b8de9e15991d019bac67acc2bbc565d69de05bc54c8f7578962e5b47a7518a5d99c4696eb692ecdf203e3002181cb13a5bcb9e9570b14451b045cd7f563775220ae9be6f7efe83f3c31bf55db2b908901c7bb4fac4a8719093081a0ec314bb1607255a357f4e36f93b4b62b44f2317f1926eb6c60efcd230577414a9ef7e6158dc2a2e3aef11c5756d829106e38e000001bc00000090c9fcfd80e746da04dff53ae85f0c8381df0ac2a45ca0d3c1a886508dc268ad3f666195ea8e909cc4a85f776aed72a28d5458dec897b37c92aa63cd526f43a63ef228b26d7a43e6e7ae00e0d9539b08a71bc505c1e5d4c7d329def19c3808eb50db2dbcdcdf2b1c5464e6f17a762f6ba110235cd5f34b7ac6adfed5928b47dd7b973b0c19026537bc21f0c15a4e29218d00000090b5d02214dbee0b9613fb5b14913f781298eea7f3ad83caf1de8b8c4a22483328d070b86ed9b800b468daa35de98b0e43bd16c3b152452f70d6c97884a40b11792b5aec2724e23b064c63721d4320668d11f3671445dd8dd294e337486e90d1cd88a84e74c83c6e48168926ed23be50ad16a2ffb4d841ee30f85ec6a9cfc77f54911ffea299b7874e2ba14d766308473d000000906d3c1841bb53a06f4cea06716bc3dc36d7743762fd24c50b36f25bdf2dd04b5f3c1549463c9940154e706b1a2f7062a10a6fabc17deb4de8500e984bf7c1e36ee3ad23eba101514c9243e45656a757c11a790640f9e0665d4f77ff2f02fd8c21a7eaf4a04963a992c0fc4f7e7d864a872621a218118a1a6b8b084c0c11f0964d2f61e09840ebf5885262f90903aa8fb3000001bc0000009078c483de56a5fe007dd924d9bde35773d1273877406e585ca0da518bfb00bce72cce915ad78d914699cf6d1621acfeacc5b86dc733d461659579a1d0b5f741a021d2712bec2c01710a3dc3f46c30a30f2f2ddd61c05df74269f8af178fc93b09ba6b6609d50720caa387df8b018898d604a85a0fb4b8e3dfd40ab9d0976bb928a1757fa864d67b62d0854511f1217c3b000000906bfbcbaa9a14eb965f5e89a2c153a84e8f802cbff83426439c07db028248a8a4fddd0c19f23c3f4bb4cbeca377b2734b2a3b4f468beec2dbefe9b632d678e57810a855bfded64f501b83cea74f5cd8ea1532b5e5a5441d5d4ecbedf31018eb003c2e7d88537d6513d89e1824f73913292f335508fe82c1366f98f3a9b90da8c3da18ae5edabf8f6fcc68d743a25a87eb000000901c8caa4f1c37d1a136b7bc0b8e13b016e1dcea12dbdd27256e8715a1e16aa4ce313d2a4dbab609e93c8a9b68adbf25c6ad3d33ecb8d9daea91ebc8854fdaf50357e14135f3cb0f5cb25ea4de27390c9018c7e2c87771400fb2288f6423e342630b2ac308e6068b0c421cef97b22bfeeb283090a6af6fe697e2856c8c0ae45b7f4f52d557c618291e40b0ef659c0d04d5000001bc00000090fd738aa0a0c555109d8e11da6f37480a6c6c92eb2d6334afac323d3b7ae4e5699bedf884dd7f6e3f0ac31e0e047729bc37d3cdc9a5be9c10bd9876c311fed97bf1180b35d841b1289ff874eec382bdcd2e1aa6c7c7933cb938cf7e906bfc504adf175db490c942d23a00b282a804eb00059f677fb45bbe69a7d6a4cc6c6ecbb7c7a52eb69e8c9660eecbc8bcf07aeb3900000090175bc40de1192a2a3b53fe5dc340e8075e8a5a4d6048df5ad52977135b1ef51ad111f75cc1d6e96e1346fcfab7dd934d3afb5f507dc3b22253079e73ba7fba5bce841bfe231c2904abe80db209bcebd11ae9715b2f8f5964c9eee1b06814d8de9656f7cfae38d358b8260b2888ee59552616c0e32548b5c249f0838690ee6e293b872ca10ddfb30443549e2ec90c9ddd000000909b4d6e989fedc93c28f7c2992f41c07a8159146c313970571ea7f0821dbe2c67306d5f8667557b3fa38975d211ef5cff59bcff19989c32098a669ed9b18ed0de9574c48c571124493c0fecc94daded3b07b15948557da6f9a2c59a5efc437143405618649a96990da9b97a2dd97fefe51b7c812a884cadc3a7ecb7acc4500d8b5138930c352c8c1e7c4559db5c148a3e000001bc000000902737fdacae8d489010fe776a0481492ddfd3a9182b6f525af0acb54f14bfde2c46f20e46c30dd05000b7c430f61c86a0c3cb3140ce7f9a4536463204878da0c09ff2c559ede10058761bcd7325b6d352102039bbe94b1ea192118564418d78019957460391ba04b9c24c3c6db4e91e1f2fa44610a1bec61d5d6d00b5881f8c4b1072caea6b3804126b5954f924fa2ced0000009005d091016fa90a33b6eee575e955da343c3887e0723147dfe417f8ce6dfe3ac2d46f4e1d28b11249d541ff7784b7dcd48b1bfa4b70a05ab932adaae462a1be1881eb7fc794886135cb810e5bb3d44e5610076648772e980167da0f3f04cc1d9f433bff4b2e7dd24b974784e480e158902c1ad65d8303a16e056c6062bf3f5853cb2aea8232e8698cedf266b572fd797a00000090d435a1dd85325b5c9360e52d2dcc8b855450d64e6d8a508ccd4984bfff3267015267f48255e133d0211ab4b534389828f88abba8128cb0249f2014d3c54cbbefc800e1185381a52369171fd2d6192cc60354328ae0173508e0da9f65d8d4b14033932442b7a104358040f80c591df9bc078c246b48923dde2f454191960738585c438d95e22915aa0a92260cdcfe2a17000001bc00000090012596244767dfe475acb366fb896b00c7ee18f46c42845b8f45f05846e8e8077031b31f26314b553667f2dc363c59304712e849e00a6aa947ecba07ad7d6e2a4b7f01b4aae9514b4edfb16df50338ff11c774aa66e0493346dceabecc379510ed422d5320bfaece0ee64be002daede3061065e76768d636fc1f3c29b19b134c5ecbceac685231c804f7727924dcb435000000909e6dd34defa51afb09251352ae526ce86fb73f7f2cb033ee9f01c8299c556a274da4332dc47ffecea096b72d1650256c4c04266ceb77143de6ed7419ecf74048de3be77389b322cef6c5c544e40fcb1703e97bec2715556918d4746bedc5da448ee3731cf38e6407eb2ac412cdf4ef7f2c7ef4f6b2a70549ff3a477960ac08ca125affc4cb9f2cafeb3b0ca8e6130398000000902d3aa7ec7a5d6ca8614e8d0838759e739814c344f44f44aaffb8b378ecde2298a837c61ec10adfca6259bbb2d502c4957706915486722ffd4b221630c6c0d4ce5844e89531d9c1b49287976c8f308a8f0379146abe38c432bd5982b1acbae3c6b052c24aa7228184ded594de74bf725226d1fb3dc9e6fdf7e6276b2cff3578f03b9b211c9827e2c8523217e1e0168b99000001bc00000090d2759afbc27e026ced7b92aef1a1c21a3fae3efecaadc7e348daf893f7cc920a9aad5e8d5de0849d054074b20b8571d3f0de776d480cb95cdb66bba67b489d34f3314b23f638f00a7d3e3b9f03969417045c1fedc109bd874ce80e5b2c90ba133d3a3ea5cba9e18f5fce03dbbee736a812aaaba41b5780b82bbe2adc929f36cd461f0a0b619e607c314fecbe5b17e36e00000090d96a2f548ea1c1ee8a0d5a5ab0d0ae42c3bdffb6712eda43e56eea46c2e9ba63634a5ce1c07439d8a62fa3b37a1d051a98666342e7340b8a9df77a88a6aa8df4c1642ba23338ebeb69e68d6fd82451c802e328fa55190a09325ef1405a69825e9e4d9a3481f232e31d1fba4bafe2e8b91641f752c037c9eb5d1b3590a681b51d73ef5207a45073a474c6ffeda8d813280000009077b2345bd8fac14ed97f3fe03f83c15e72c71c1b5708be403cda582aea707460e4e87f1db60e1fd1eb396af8b5db488b884dd826798a8ac1b5b673641a7dcc7d649603482b93f4e882c251c16e1932340a802c3931f46c21beef46c9d65edab51de453032d3f923bebea061846e761531e7758045496f471193da24b203c7dc80a2ebade189457c3bbe16e9cbd463b5c000001bc00000090ebf939e3c875e4cf86612db9daf9af16b3a7262f2ecfa092817a3003542e8d4acdcefd7b3707cb1e50595c0261f97627d0db381a5a68abafd2423b9d06db28de879ac63416d88d332f7b4ac1a7a3920a2824ed2e4d88e65d681f0760767e9a4fdb87bada2ed34f46ff75cf5aa44592240ee7a507c357c4d1d284a2c9715d6a2b806568b3968c31db87e169f71bf373760000009088adbe8fd897d14ea24e12fc5971d006ea4e2a94610e9e9a296241831a806d64accbc6e6b31a0fa9f26cf1db413a4158d201f1b7cede1057f762bd8e0b38d95c994058193445385bf6344871f408de2215269a797c685ede92b2c0c2908bac69aeee48638ed91cc099b18a4602fac0d62480617aa0d152b5d89ce4e4136a3e97746338f59761a758767b7ab02123fb04000000903314fee7070b11a4cc12e4cb2ea0ea148efe941e4d87cd1fe0a05b5e2292d56bb0aefe9dd003c71dae74258fa7955af63dbbe76e39c620a509b514844a9de831982122914c5339966babea425c17f6102d1075d228e120780edf0d6a101205d8a82c5b74d5e819e9b1e39ce3ad1bb44811e82eff3755c38efa9363ec7f9f1685ddf1bc01c9aca155a8bf6f9ba7124db900000e00000001bc000000905d9e901434425344cf75db31be67109ec6002e3141caaf49c4449640b7d0000eb2a1d494216af78f37ad68404d639fabb0f609e11e1a76a21f0a6dfe75146dcb659890fb97c54810d76e030ea8998ec80154fe78ddaee7db321407fdcccd504ca7142a1d932a22771c67bfd3a930d134096e940b4478e0e37a9a851ddc8c40ffdbc86a79b4d7bbe59c846a4ad079c9ef0000009062858953192263e0ade35140b03a2868a1f68c8a93f50c296de994466b4fe0a6225f4bf9f0b9e027152a4a2bd6842930352e4e59f6134d0f4f14a6bc43cc9cb96021b5285b2ec198bce333be36aa8945048b03d089168344fe271820014be4f869786dee42cbf5a7c8d7b3effa5b4ab40ed9a89e205ef8e61be31ff68185c7b3f7d5496c33f332988def3c7585e2bfa40000009055a58fdb0c20271cd82f9addb17d5fd7e5a74bf34ad731b06714dcf6313b4809dd4390706c399f4582da45c90b1c26b5678141d82285394330d96de61214c3978c596908a41c7cc30d45631d24c49ea5118d6c04e09e9d095f1b7df21776996905a446667587b3df36549e05db9167a21dce80d122d933f7fd67a069c5bbf5143fe9277db320e3824862fbb1c3f04019000001bc0000009033ce0c97917c719d1141edd08615882d63060c6201017b42817ff3347e835ba1e63388f4759821af18e3c9d13ae55a45ee2d365225019b970118f64bb6b6431d28a7433b196f1e1235d234f97e656c3e053a343bfd928d3ba4defee235338d9700cb04e328f059966f4e18d3c0a872311569ded9ce842e279452f6326c8fbc4e055216e47ebcf2797271a57856e6874c00000090b633997bb23968421c7331ee0b6b7a84c24ec9dc033cae28e2e6c1c62a38b2cf174d0871cf5a84359b5cbdf7a41ea26c7ae1cb809faf43468551de4364cab995ed1b6a5d85d3e74d38a2bcd5cbace567096897e74cfbffa2d1246d70bdeb53118d51d8997479f8e56661f72355001f270d3e730ff09c1c8dab25031df8c062ead31b70c0f09440eedb450ab746f47a8400000090a41b0ce13c6521a36164b3bac101b3925fde557c9804fea41b20580e930faeb088e68210d27870eff7fd1f796650587ddefbaf7ad940aa63bfe9068e6600de648a78754fb7113d3b903cedaccd702ba228ad48a75e6fda7fd47c8e42ff9be4a8d83422dd2db2d088c2a01d54053c48f72712323da98a1bcb5d0f3d0c2742addecffc9f94c5f564ff724ecfd9b8aba1d4000001bc00000090bb81822e8be18dfac6e1654c5b0e83435164d9b84aeba59df89842487ff21a7eb58a435d0c20e5bf5737aa8e36d9ed7aca4d62dd70a71113ccd18bb02e507526b0a7c93c46fa73dc73fb277f8fcb16980074e020fc7790ea6eb9922786c4bfc3c3e242a772e4da2c83afb2b686ac31db1f68386f85b12298da0964f2bd9482e003d96f5e52330c61da84dc48259df572000000909a5633a1a5ffa95b0bb0cfb8fe13a2f856bf3f0b1e1ef6c067a7c01d95e231ee3c1f51d71b7d7bd46b4e95cf4329ab557a323183a5ea4b36fd19011a8856650a63f554c2cc0caa13cbfef616980ff0ad08fc1e8d5ac268f4489c87e4e5eb4b4e6b25dd55719ec530dd1d685b1a5ea80618c00ff1786fd872d172df99618f92aea71fe00e7f021a071a9b9dbfce47c4c2000000900d2017cc70254c6e8c8dedf5fa11494d9489fcd858c4a3fd1119b87b32a56d01cdeeed4e6c6651688e29952d287dca916ea4216aa4b354808bfa8f2b2594a4dd1a397aa29343a4fa9bbeb6f043a0c8022336363d3200be9aa3d2fbad0f583ebf957a94cb2ddd67dc750f1c4667cea844088fdbbb7b9b032de9cc4dec596fa0f38154b3ff3198e98a60df575183615025000001bc00000090463d84e1371d6fcd32b29c1051adce0b15d690c6ba46d4aeb3f96502cf51ddbe96b5b94869a757a867b62863b59b881e064bce9fe875d08cadc57e15a830d156ec32971c75ad2d2940ce37c35c90a745005103288ea6aa57e4363f750b5299b9ee6d3319f5b00bbda34cceed25a3196010bb67c780eb08a16dd5e25b91880bd95f62db19bae2b8bd3a40743a019e14a40000009080bcda014da3d2516f539b71a9292e4ea2844649953288ce59d6c2164a3673ce301313da3085576409f086a60eb22c51193e891a8fbb22520a05c8a90d9d3dcc81f405d0c8b7327536f2a1126d6454ab108357b27251c481edd9abf8a14102dc0eb04bca540d26158ee09dfca3cd0d3d124a901f37c9a8417cc06d972b16cf4bb0b4a1054c33e1d6659e5a49b7908c9300000090bd0d69b106e418895e633fb3f89c57cd47784ddff6b12a6b1e17a451845c2df2e9abc10e2dbca4476ed4f8abef9f735c29b0224a5cacc49d55ec69720cb3d7ed299f9a1ff8b1f192a6d2df714db8d9b90cbb626586423d899f309ab8bf7fa9e52473d2df9b586d1fb361e250c2869f0a09e9232339982d7f6e6a08518c47840d6bd3afec0a2ccaeeb9e9500e66f18a38000001bc000000906ed83ccab5a3915cc7ecc3d9e887eff4bce78e4bb750f06f2161a464a9549932d05b981e5c1b803d83e3a2f49e5b46a33a90abcfa1ebd05540aa1675fa770c4549c6f1e6be824af2924e82c9315172691ed2134e7e181973b1f4de5a7a668db095c1febe9cdf8c96e121b5008e5e51ed29c88b1cd9851cf084d5447ec622dc0dc9b83fb987176ab3097eeacaa1605d52000000906dbcfb91dd198999bcfedf2b615973d4db1fa60325ce7a103aa85d338bf051d76af1ca95c503d6ae8b61bd77b738b6b069296002e7f6373c8c66b4e45ad46c0ddd294aaf7a4d8a0d8177ee3f821e00bd257eda42fc73ee24c008beb62220eb0062a06481c0b517201c044c86c209ad5f0f103be0d8ae501501b7d2670b7fe234d3d6cf8ab505c94ed1e60198920730c4000000901e7e803aabcb23929ccc0da5bbf48b8a3c4f29ae13272e4f6f9b899b90792c6177a6b62650a1fe2bc649ca227d59237ab930cb39e1607c80a82341eba7e8c55aca892f2ae5ad9a303e68f0ccae8906bd1f3f99fa2cbed22666e954be4ce635654bc0d8a9c248fac9d349ed816f25cb372b45d23bd9794aeb9ef6b92adee251ccc690035597167b8ae1511ea2934bc1d1000001bc00000090e4f47239ba5ac245a637723b5616eeea22b678689eebb5d64f85983163743001bd01612e600c4c1daf4ca22aa561418817c8b4037d4ddfa1e42cc0bc388a36e8cefea61210aa834ae4f4d783825b7bce03c6ff9b1d0cf55270f0ebc197c96661e147b3b7378438f9066f3b2466713f720a2e4105ebcbabae6c68ae5c00dfb6891a20f612e4b4f09b03f203b79177fac200000090db6ccc8768f59553cb6ef372df5cfb1c3d1933498eb1ababb045c84601037774154e183639854efd1f522f829a3e4b2fed62f2d7c68d75a527d572551c1ff887010c031e1f69db22d08208b1b1a512e924593ae8478cd17161071eee8be70fbea6af109f9df7069eff7155232ea08e7c2683f71581306c5775a76c44ea487128fd02da4c98d0994adac12a06c340dc3500000090fe37d3a0b4971d7e232654b304e746f3e01dd6b9c52620610fa5fe41fc3be20a1b248f0fb76e176df3f65fbe82d952aaae626c25273138875e7edfafef2ecd59073749ab2783ecf7f2ea3b1fbc11572d1391a220d987a9efc6705464189a66ed96fbcd3285f31f8fed01e360f8db77ae12d063cf0229f9840c630a5cfa23b33aeaa9f4da5430093ace75d970adf9a307000001bc00000090bba25a65394066afaa0c05d288fc26f6be3d05a365423bd4ed025bc81e1a555b6829cb0ea4d829f526746789c541cf79698997b12b002d8a5be07d67b8bec7e1cab4ae54b0fb7f3e1391129a38f9a64a023864e4eaed14ed4248468e533224ad63d39c15e9639d6157979ec07558e9322ea995c8a27591a045db42869f0973ffb47838f34b936d84fadb7bdaace4839600000090050936a20b7d6d8ddd899ccdd496e6b92d021338e339a4712528b9a4983a05d46171b4fc90b8fd031e92ed34fb30aeab1b88cd8fb06fa9ff660fe511a88c8f64f62650844521ee3f63f04f06982010771175a4993b65d03fcfc0b6e708d9a5a60d4d8f45e4aed98b5d16889698741ea61f30875d64382160a24c17d3dfcda868765536314d7908f255a2ec0cb5b9b8bb000000906a43e92c73334db7673419e25849327aa02d5b39c2c4835868e1ec9ce524e1ec76299f91c389e69a68e42fb65c96b77c88febdffe38400e8ec1b53bf7cf8200aadad4958482af5181699f3a1e74aa6b02f7c5a28e905884065964b7b11aeace02f852a771c0d766c05f086880307d5ac1b71e4353de1f37012f0b18491c14baf02a3aa85a0ee6629e2c01108ea672d06000001bc000000904b4015762cef77f008a164afac9bbd3148261c9b19b49e7f27140a2c41bf7289002e6d1f0925fa2e5ea0aedd65adc4fa2956531bf2408d88d3f1fbab21f6ced820ef1ddd3b61a38b82e5989770b49de6276a7437c34721ee1c912a31f0cdea4c72223a52a355720a053ec32009d9f50d0e15b6fed525b528b4cef9e08db67c17e96b88c4816ab139e5981d3afeb64bee00000090a7790f310ef59dc17960ba9d90d4f9b1a720e20c86e6a17ce2eab102db72f4d5087fcdf70e812494bf860df38d28bb1c01d7d024a5989d433d5fd018c5adab79485e3661c504b7da54e8655faece106a0238d77410da7564d7aaa389f4799553a6f67bc5375da41efdf369a713973f321a62bdcd0b353dc94411aa30ad5649325e207425cb5040c11c56e2415536716400000090d0c1143a240d3ad23518a5d2742989b87fc99c81d337f6021e50cdddcced716e4e68cbd52038b666090a1c86ea13cb0c17bfe0a72b8070b5b33046388d34594123e671a7aacf3a919d66008f27ce0a871f61da257170e276e5f035beba17781ce12443bbc1f1e956458dd3c6ebc7e0db0a69f8e7a4ee1cebad51d7ed3be1d71ef3d5cf55c5468918825ce6e911260eda000033a000000ce40000012800000090c1184e7b0755c6ee0dc5f14b406042b8efb6339ad2c12f5cc5ed4061ca6fee9a4b8f79cefcd9df3d109fe6d39911f36369cbe704ad90f4a47be6d797f4172e0152396968ece6420a1b7786a309abde4a1a79cbe13db148d209db3525f1547d10bea97ecdf93393791d8a31a661b3866511b627360b72cb14be4e6882a5dc3123b2d5a1839dca6561db8bbfc7a9ffb749000000905b7a4c09dd1535dac6da83bfac0376fca09ad1b0034d3ce33b9c73c92b8520968074490340c4aff0b06e4b06a1abcb1eed1494fe5e1018d6e58901e59bc9ad2a0666898a294f417fa8bef5e3f8c3766009fef5510a2d265fcfc151e01b6f99e08c315c92b612204a40424ed07b5fecb60c0d0e487a527641365cca14f5c60e5b363270fc3127e0ffef9f47c2cade3ded000001280000009026e9ee78a7d701063e9cc7b36b687f8bff2ecddeef3c7e66045f394db6655da9253020bd876e8ae7f5cd909506ed4be56a9e00b28e46a7b8261ac8fa545316471a350997a47add04b109aacf57fea500047b7d4a43623a4a1e7b6b92588e92e95f87aa50d6ab75c6dea8d73f3853bdf82c4677dc721363a2eb6ddcd2dc88d227f97aeccf21e7f69e0308e1edbc54bbe7000000905eecfe3c64420f6828da34ceddf58a96bfabcc276d00499b18ff4f42211f4feffc3be4e34dff2bc3645709bfe78e08eb33c887f8e874f7e5e37eb57cdc56e28d2b33fdb5a1d252078d9918922ed291a12d633a12285117a113cf332aa84a01e042b13b05d1609886aeddd42f39e4393a27b91cf67bc50c841c7f293907290a86c9bf897e5ea3eaffa04e2294e4d4931400000128000000904d0af568910825d85e5bb2cac0851b244a451717495a63d98d5b1fcf86ffb6f9e2f7698fe1c399ee9ac779d04dced7db03925d946632a1cba2c7dd5dfc06e2f95dba2278bb8b726e19598146eb23d747090eb94573fb8cb904ea17f9d90e9fc18a02a300faac3d1111d4ac31a8febc610ace104a9da0f91322648d19dbb6b0e01a1897f89359ecf2fecfa572f0481d6a00000090c291969a1c6d35de42b362babca4b8d570f286535ae3bdd609dc5537d9e7d9b61d35befe4e6eeedf5f04931e57789a3db96d31f68efe8b196026fb73fbd9c0aa5276ed617eee1e4f6bfecd5a436ed2c52ab8fbaf33dd9a81a93a7e91128757c1c258b719cc30354dee8ca593146cc8730dd4df65f08f4571d0ce5b3bcb209d78a40a46bbd0c6a378fb7f090496e9d41b0000012800000090b1ade0021d2794a5e966b881cce4b0dda94c0affc33c2b1088b83920ff038aed333cdb095e126fd387ca4ffccbeeb7c40fd4ce9ca80d5e795269fc2b4df4a14a006efa0e221593e29c27aea7c5a843622035a9b9a9e9b129ee6e1e6c133586cf3014bd803bbe06b24751e7310ebc179b1d024f95ba503a1fc680c8a13eaea6d3a5c21d077b1e2bf0e7a2478e15e0f89c00000090d345f19fa6612568dae1484f72abc5cbb5945f3392101f6b728a9365835743f0fd4c7eeceaef6000c919718ea8ea0c2fe4de55441dc0c21633c146ffb6f99f0408a4023dfbd698bac17addc336f5034309a914583b10858a2140983516a298e13521eb51e55726c3518901c546fa9c35205b0343b9fa069e31bde3bae3519857fe9c70b157b17930cb2f593818374cae0000012800000090aed05149d934174794eb20441b13be36d09ce547ecb9de43c750b4d231254d00d268147308f9c26d1ea12f68035479692e36b02c18341e58232bb94aae2bd5495242254268f5f2dd201503be6a4da17123d7a666ec58db702fe384359b16e5e6fecf5791da00ef1e33247ba7acf66e6028d946333ec015df4e9ea7908b4eb2c1b832ff79ddad5c351c711f085dbbfc1d00000090ef35a2d551e37c6ae54d8c571338a10bc4599c2d372013bd3108a8245317168199e1c19e61553157e155c79fa33f1c74510731974bd982b3c92e3e05ea3a5ecfa5101588cde1431fdd447448677c2d192871faa6511912e2db6c1c35eb5b9fcd6c1411da102dbc22d5bfce7ae59b65f5296e84beb38b5e3c5df5091b5a9ab20a8a09a51402625b47e3c805a24f76c0790000012800000090589da53ff3baf70985a7b0621e9f80d895fc3eba5e706c89071f00489570947d0f98cec0c624e6ff313de46c29f56425faf01012e7c5cfd0d1a87f94e416e2ff961e0fab0a90cb120d0e67abe3e2a1b10c6ed2de76daf1527143306f1d898b0a70b98e4db4ff7aef55d61db43a01bc222ebed44d7c2379c55e9420799797982a7bffc9e38979d08fbafd78f5171ea01700000090a6afb0a259765cac6b666c6f034a882450d2b5e9369fec7be572fb36c213773fd6d10d4cd9f9dacb2d25e05eb6109ffc80a52861a7340a3bcb2836b2e29d56f26d9b25eca2d2200c902c045b2b9b2763032a5cf3806d466e74fe15b3133cf5a59899192c5e21f6027b17c6ec0372eecb2c9b75b6ebaf91e2c23e9faea95b9c2bf65c1b53b4ca892108bf67f624c8066e00000128000000904e28d89d1904e29ce2264ec4150901703392ca3cbd97aff99fc0808d12050f42ed9b0f744f6167b879b77942d5b0dd5de88d5897266792ef5ae8275e3623a995f1fd946fcc067a5bc551bbf50b31b2cd0b80ec94de2f2ef8c60deb916a66e102900adf85f14f7b2561cdaaddb27010a50f37e725d1f1d867024cafa82b0b8a5a4cb7a20569787e8e9b0d91c049cee8da00000090aed624ce834af128dc6db3845153382e89af1b073151b69cffd4eb17191e68616ae15f22c5bdfb092f3fed1e95b9277029ec240773b410f2b204aa467bb0d13f9fdb861ed194d95051027facd2a808b10541db15d98128621487ec9b6724c1c7db12f548aa9c5c915311125882d7c21205bd5073bda29ead5fa09d565a6d0229a159161f5278a79e013c741968f12c8f0000012800000090987cdb784f66d218379568f4421040cb5aee43825cbbdf88d6e4738907d3547c2fdb465b575bc2659105694cd8111710b8fcb52c0f921837488965f16f12081a0ec79e1971a406c1d8801bdfd08f80b70cc408527a9511b7b5ac5c6ee750f38df3d7191bab63623618c8b8ee32603cfd131cb32f36226efa7fc24c3bd414e47482640bdd4b80389569c51902e5d42b0900000090a6517056a78e45510559fd820dd603e29c873a2e82ce281bb75203ccac0b7bfb43a6d1477ce3a4fbbc129cc4c6edad75c27203495e5da5f6742e07a80adfa8750bf286596659d00c18623769c0670db3245c7b7c40fc43702b77ac652da19540986c9373115ec1b80f3be5aadae33c4102aeee8c3004348f31454278a0665a919ad30846fdc9e4a78a50587ee328a7140000012800000090429cae0a482159c4614f009808d4c5a947b0d6b7e1a88ca583029aa07911758244435b44f032eca054d8fcd001678d28ca6e75214be0b4a570d2169b2d9b7b473d49d24a7317acf805b9f56cf64440b611c20473f91c4a8a870b27eb47b4e8bf4afc2589345ad3161489313bedd168f817b7e3f6e3b4c21cf6dd6c0d8fe10277eef8d73e6fe9f817c292fc7e4ceb64b100000090a58756ec8cad8eb538e4f64e3f75ffcb3d0546fb20f68071c291d18f0de9def4698ef8f28a9fc97556752a9fc3b7c597eb38acdead62359487ba67f88896aa1ef2636d2d0af55b37f5537a15e773c929053a77479f6482891870e3528f4bb5ba1d2d1d2fa3b2f8b3ea56391a805c7c9c0d083c802cb66a0af353d5595366d03aa71f82a0eaef1f761b45a520c01e1e2d00000128000000907a57a7bed3fa0d54aa689280d74ebc76df1429c9720d2b0ff5be7ec8fb596d69101f337fda4cd588e30c0c2c1dbe89423c75c171275ada2c268369ddac2ef638f4067a6276397288e32947a4349bd19a25ee51ffeab4ce9ed6e39e493616b100c4cfb510dabe06c0d454107218e881b813e8f1f9a709af35fb433aad0d81433d68e27f2598e7d2b1188cbf479ea8c8720000009018a5679549bbb4669eb6178f6a72f976404fa0db21f5e9e42c13a88486b4cad2fc824bc192772707d1e581a99fd109747eb47fce647635bf28d5f9f05ce649159b348dc794b312356d162ed18090a3c428a602ff031a01ea69f36b9f927db0508625647fcb7ee81f68e9ba7ed361ae880d922d4e153f53218b70079854c19dec9f7940ce50237fe20183b268e48533b70000012800000090c92a11c6b4bc9ab5f60d77a08e9aa4ecda2348b783b5eda10742077f96a9b3c7d8cac2a72d5d97d9975d04fe4b813e2828a4ac02d87436bbdb9f2cf1f6ce643b6c6a6cc4d0056d80b6a7ef8670b0c5460d86f5801938fe7b25617160bae750623a8e443501ca7fccce5925b870a4a94a269a9f350f2575b04531e62e27ff5a34f931811d9aca21685e736eb28d8ec28b00000090e7e3038939ce40a8e9b47c818c462a2411bf8fb7bddbd3268254e7ee95903d9ade784cdef15dd1fa7944edc35718454d45552c13f8445e6ac34d0b44baac16d2693b309ffa5f41a5ee6d53fb06c81d2d2df1b9e2110e5ddd2e9421214bcc3353eedf6c65f14e69278bd583c4db265d332e3e6c582cd17ce49ae9f86c850fb7a8a59fc99874ee558974d00cb6f328e6ee00000ce400000128000000908401dcf6da9816268685fd337dbef7907a04b8e20c8980ee800970b949175ec2eab843589ccb5d7dce27d265bb8ffb9f7e79b759df627d1303ccef833bc6bc6ff11052a610b59a4d24bd5f13e12f17d8034757bc55d80d42b79a753e1ff54ecf0e93c057e41ab9cca9703623516ba3e521a66cdf1d6f1b98cfb16cbbd8b8fd14247ab449eb37ff3b4cac3b1672249df1000000903974d49fe587239c2817b4ca777b1dee58cd813b7d6f100961c1cba7b8a351f54c8c8e28383b94791a4218c586848290e3e6d64a5a9ab06a3d3d986c24757a1a49b82236144ffd4ee4e10460a1f30d4b1979dd8b881befd6f0858fded225ddc9159899f07dea2ff37c2f1c3ae27a7f301b95ca34ef39ab2ae4a4deeeb7a8a8b2a9596fe1fb41592998344ecba54403340000012800000090f1edd02f1bd63304a932a027779c61466d37b914e0ecaf0b2f286d3d5dc5e2861dadfbcb589d77217beab81952c8f0ddb93bb28facf7c5f5e31ab4be6d896210a499655f77f3ceff5c716ad1297bb3210294688ee98a7df3d311959075d50357c119c6dabd4c2a410fa0af38eb3ac3e41710882ed59f01d113367751ec5dec8b4330537833184a2145b90cce77b45d45000000900750852f50a3e7b313cc098d678be62586579d65c9bb2e80d1f7b32fdc5745fd7a2f5b651c0bffaceffa8261e0f16befafea6bcd4b5966f3438b9b6c8e76289f1ec3d92711ca82050be2d9e8e546120f1c2b4b753f505d42e55f2e6eae8414a0a2b2a7baf14e2d096302ca9db5396f8b1cbb2340c078fa1b5d6c9fc297b63bd52db343be13e81bce5c71d4aa6133b79b0000012800000090ba594b38e0d1ac56d7fe3fd05800f290f87fcf4e6a352d1362cd615b45bf9e298657e4f7c5dd76cc44c278bbbc85ab85ec834f4958bdb040aecad06ccbea6ce0ea919693d48c21bed882c02c9caf02a00bd51f921165e33cf40ff13a82131e2787581e6061d3bdbfe96545678fd35b942455f8ef85598fd284608aded3a61d0da42ada53b00867a8e3e0383a0345973f0000009096253c8c1b2bee2a8cef78871dd035aefaf17ad75ecca21fa4f68bc4d816eee4cfc67f036904059b0ebf3e5322eea2a5ba833ce7946f09330475c23e04285b2908be25e6b5a6c63f01a3d5ecd56a3ec02fecbd9cfd67fb4d34106c01220263580c5b37787b50ddb50363484172c7d7fa0c5690d3969b9db328dd83df2634278afa2b831d8087c915cd8214c91865c7780000012800000090c32c08f4f14e0afe5c5634bd2fe6afd1ba063adece33d45d9e6163cbfe1ff2a6d8afb96c24bdb3219c6a0ce72c6202ebb7b6254d870f4b1775fab44ec5613bbc1d96f05c1eba25bfca5d61f53dbc100216ee0ca74194ae6e09c4aed74c527346602293501634572f008e77881d79ae871a9885922afc1f9248c833478dc5fc8a8348bcd19b9bba09b3ea2d533641ac300000009034003611a5b03bedb91b1425798339d79c0c6f14d1805c7bacc9d345b759e23a0308e253c1484da8d41f81f426afeed305bd02dac577d1f7739abe5c39a58bc55cb334b89cc7ff792dd71cf65dd17bd91b75958d3bd4c6ab88fe8bf8e9bfa60d4aef216eef37a44c4f29ffeefc37617911d3f7eb33f7070cc6edfa403074ddf6d3c29e77e1fd234208bf18a8d608ce9c000001280000009048b356e4dc8108fd6ae59f920c456c473b64baac459f879f18a816c25a1c8ff20eaed4d523cc6c502a0c1791b4432b292c15c8b4037f05d8d64e2396f4ec96e4158dd517b7965fc58ef9b9b99c3add0624f4681af0c175ec471dc6c72e3b139474426111564320a0b6507d60736e9ed50f824ed3cdf06143ad155087622ae67ff04d6703ba5bba340034ff280d885e0a00000090342514486b0cb38c39efa4038f06924343027311710297789923b882a9b126151ae9e56a8835c7769e252bf5918b547d27bf193174a1c383998853151201f9b8a6de722c872e1ecf30b24bf071136c8919346d14cfd311becd47643bf7f0da5075f01884b7c0d00ba4e8bcca29f01a8720ab944609dd2a606a963c5dbfc9207eb66f167e861fea8b430051bde7781ac100000128000000901ed36592c402a8327f7b12837bfc300e127ca0e52e19da57ba3129b2801551f897e34fc6eaa74c8376f55f40214471b68213bcce2629361bbeb895fc67664179bad65c2be68f44c065c55ebc5e6f09b02e2a714c756c0545c67c30a999400c6b64839bad523ae7e9d8691a4de12f7db9101b26dc18a1bc511a1a2c985f37a9feb286638988c33c62cf645e46179de1200000009084276d9916dc21791751b9ffab9cfae5d1aaf850411b0637fb7e68c0fd89b5da75146d29335a4695955d0875261afd59d3f9b0ca89cde21307e565c93cafeb1df31bb788223fbfcabc410017020595e818658a7d4c583ff78a5648b8324ab7bf881dfe15e7d36b5488b4c246d94be83c095a7edce57ec7db60012d39614708f4635eb9f50a93e2446cf6c36d539720ad0000012800000090695d9f7cd58ef8c49f943a818db09d07021cdd83b261af2c0913997f9dd439b2e194dac6d278a7308785b9529df1821715f62a8da850a115efd64fd82679632788154c12d41235cb31e46c8fbfc3507b151da8f80ab1837781012e066a466579af1dc6d4719979e63dff27dfa260197717902118e98cbdd2a0e6af4575e39cff0972c4899454806512bb4b8eb8f7224f00000090ec488d954847bee731e022a6ef11a90c2268bb1b7d984a9d59d66eb88c591fe05e0c87b0af02e1a88e20dd548168a6743f3f63c1107676a0d6f3e7ea2a1497a4ebeb37a739c54bdc59e04b9a188f6e4d058c64f9ae251d48ebe64646f3b07e840e0dd9107f61859ec547517a197fbfd42f848d63ba7d426ebe4ad3a72223160b2b78125f4f983d73bc2215e9f93bd3dc0000012800000090fa087b3e33f8b6bd321688f22f77acd28e17cfcc0caec30bca355145b39d12bcf2d57a0593acfbd53f18f654f889e0e520a6274bc775cb19667b6ac53baa4f1fd9af5bb4f3dd5271651d2d11669093b20672298312f70d390c597ea8323e66e30fba50eb7bb810d59daa1d18b28bddc129d24c5396f383e850b3158335c7d5c3aef519c45bbea0e83d7923765320cf830000009090b243e964605ef74f622fbf4caaf20b7651378095efaf3842582d632b19a79d434daa769eee79a781c194da796429ccf0813b90f5c900c4928e227493a6ad9220247f9c255770d3945e36581f62810a25b0c77ff60a5d096218c0cc56420b40a23f48f3a063923d3d45a0b5597d3fe01beb2465059b7e4fc607386863bc0a6e246877ea25f879609092bdac7a5f53ae0000012800000090f2db3cedcf7511667838aa21f47fe46f2827e92117a1c0c365d21869b528487ab5140e056d3c9f8ef5e9735f50d221f7d1d9202da6aab0bca22c4098dbffe2b01db1c3694dca9cfcf18cd5922398a357285af6fb67a44b7ac699938eafe52163890bac147fd0fae70e24571fef610a6a2820eecb6df541e5dd0a2b194fd3cb45d49251b22292451fc34d3d06a0c29d2d0000009098e78c4a14dcbeb5b4000a9cc0752e0f814be7f200bbdd234c760a869ec69a17b1253bf26ed20a34d38baf6dd7db7c2a9abdc8cbcdc0c1d30118b15d1ba0f71a1835f5dddd3d42c297ec67612784e140037555182233fa5fe019034fa2564c9d4412652f5d1e3a7561fa118434a19b860704bd59ec6967496e96ab1c44bab88e82b1d7f664307a13c98a6546668ff00300000128000000905d07a9519d10207d59110cf39c1d080324e45f228535885f562fb3e14c6cca52eb8ae3bb49fbe3218dfe30aa1cd70ab5326e842283699ba8e5374ee9b14de819ccf10c97dffd5f7162b863ef1ce0fc3a12c7240a0851c213db71afb38f3ba5f1808b0d782c75284623f14a9485fd24cc1e396d48caed5164c302e10be75f95a2a3511fac0a250eaa7085ba4dec44fa9b000000904bd5ba92cab181da69af3fcfa96d8dd4ef89f7f8def21b17539fbd803d97702ac6839050a44cfaefd0909ba4377f01e153b005cd2b11b8b628accc5d16b61cf2a2eca36b988b95e956a15d3ff6f4a5b513ddae0a0e9d235cf87525f0c768d75e67f03a03045816749705e84ba7020c3304a39b4d12d5ad0fa8feec5d294e9de7fa850ab6fe1a2c61ee7c89a3d38d90e400000128000000904bd184043e931f32b0f991ecc7d0ce2bee0aec90777da5d576455e3116885e8d7077ab03e13eef2f1e7a4b16f91062a32f4b84e62c75b8a676565c755a767ff1c9087665b85d0a6f84f35eea9c3802ea2930720e52efe5779e259ea6b78a2ea6879812b82acbf9abf3e700a4dc87fe0f20d4bba5c57fc1d3f845567759854b1cc8d11604f2b78a09976218bad193001400000090973882eef74840f0ce0194f5bfa5fb01b50866a79c725744b3bf55c5734df3c2652b64bc04c8f07bec3d79d89359c895739765b34602e5cb7fea63b6cd511800847d1ffdbfc457da3d1c59731192bfe108799b01c776402379432c1dc41a12b84d3538ea6735e88721d2b3d5b6cdd524130ed309ee0705d5a02d3b0b68edc328f852afa06bd58f94c8ff271aaa289f2400000ce400000128000000903eac57414ea3bedcf1f2968f627508ee03d212cf5e899bf8d372bdbcfcbf2bf7587189bd7b887fecd0d939fb9ee75ce98fdfda026eb40ea3059c9b2ec74e692fdb100159b93475428298280d8ce98a0b0b932d29eef75e3c6569ee061cef7d90a513f74abfafb54f73a723153343b7be18d031023c416f22ff2d6c959de6c32458fcb265ac25b9d63c264c13dc5442fe000000904a6ea2e24e3834edfd8c5aaba55805110e2a68ada426d12a6b08074e5feac03451a4feb6c6fb4f0363d6e3924d8a37581596daa8a004a2046852ab2e079b56c668b02997125dcc6974899a1710243b4f048dcfb219f2753cda9a88b003cced65772cc2672a3657645e2d3e2c50df6f952bece5edb170e4cb61e62ecd58876db301a2d05f1e77b59b97d6983b3e4595f400000128000000901deb2afce84f901be6e439aaa55da208fd7ab557f57a4aa70691370957cc5bf118f18e83f5703cb6e7ffe31441643812f8bdc2ab892b446818ebbbfd500d1d2b12608bc8d6b044055fdd1977fe4c93732a43eb38369b703d33d4d751e397a3c0fcb33de1e30e512a2215347703635bb927528fc6ca0032e35c2ae24d52a2fa0b09368c63cfa5d8df26700b308c4f3e6c000000900284bef456b23bc7dc01e8a18ef5c05e3de5adf9ccf806c99ea1af491686782542fe8d1cfcbe871a30d0a1c5ca26b6a6a3672cd9d065ae4147acd4f022df63f16c2002bdbb6d6f365cc10aaa7b80d98528d6a4242a74bc444ca930f00cdc3a5f0d4349a4b5f5f773ae4b345901bdf5901ae9606353bb5470970356efa80edf6ab74676230bf85140d2b66aa7fd91815b0000012800000090655adb202f1c7f8e98496091660dc7e47e67a9875bb6c1231e96f5866a88d2000ec7289c81cf3321783af1518a15eccb22f7be81c99d023234faa51e8f6b193d43877dc36948bc6b092642b8ebd57f5322b149994b3c84c70e5e68a462b834c67fa0aa089b27c69488c6b397e1401eef2733e148e00585dcffd05c2b5e3aad0f7879e63336a9355877b8806382b5ce740000009033c23fd60e541cbe0fab4d1a9e641f941cf6f384101dbe37ef7261074815f77fe47d0af373d4e338cf03f986980e89e4fd5b1dbd52be8d4586db6a28d7817d39afb81e3bc528a5b901b342c9d8cbb3b10472f00da1ed3680da643cc1f70a2da2d227faf1982951fc82b75864d4898543271ac6350adc7dd228c585ed9e5a30a664a44f2272cc147d9bf29bbd219754d00000012800000090e3d557c8675ce12ce855fe78a0b1d37e7a209a46f6a616640098650109ee9a505a8ce710e1fbeb9000c08bafc7af67aa12ad3e6426ee599899ceee761ef037d04aff1aa82226b32150a0ea81d84e4dfa2d671ca57c63f9d4de3ba366641fb88542ef641fdaa34cd72e56d74a72f8973b06e72df10fc70c87e13f20e9c167ff64e038334e4557f5f139e72b21603e7e9f0000009061423b02328d89019cc10adb50f22b53972773a19f860aac9027560250e51f4b227576812c2d56620760266e20b96945947cc286cfa89fcfe611307f233b45c7f8aca23b9d9b968657ca31a6e6cb070a276b6534e90abc5283af72c2c05adf5a9fbd0dcc6b6db5e5f453f68bb97430fe1c0487ef65d84623ea34ace050cee02cfae3df4238efb8d110e0ee7e1124fab700000128000000902d78ab4ccc8f07c205e1314ac8872e21b3efaec89aadb71c581f2fe326c0e8ffb53a600e45da317b9d30c5e30186a5c46559ecb6f93e0f94be278b287ebbc47a0c93ea634939d7e7c6e8cbc5f58055132310adf5904cd2ed166f76ffcbc7c72e7d343a528d4073439b64f0e4455fd5d8079f4d63dc79933d303cd006e04235f022bb0a1c94f7929f2a52305d12ba505e00000090a9565c8751da83699debe390bc706b7b533a82de16a3d0c6d72a731c3eea7cb88e4e6d076b308f8526003b4704d4e60cd9c08342b7e0aa84912c2a4367623fdd17cd62c575b110b03743200936ae352d04536ca1cbbaa118a66c441b48071cb3fbb984fc5d7ce2d0c3f76c5a3b85298c0b1ddd5f6f0396e7d02aed44bcd18de5ae12c672783da24669e13c0ea617ee1a0000012800000090f3fba8f041cf4577b9e7162044b84aee21c70227f6d4ad7a26670e92e7800b8c31f1684d75beacae697bef2062d49ea0dd146ed675eba946a2eb29d81d2a844a3f922ddfbd49a00bb7213da733f4c66e0847c63d905417bc9861367e1a3795a9b62c26d4ccd14d556804bd149eec56e50427c858b08ae4c7058453196d4f8e22503f5d78d2fc4ca62f148b3392c9456400000090d1e58405a9c31ae318fb7b80abb5cf63f82c4932514e5b825f1be5fcf6c8c53ea74ad90dbe8e188826d2f1e9805b85f4b124f0c73d593cd2384e102c5b60f92cb7eaf01ad14a7da052cbe93698a123131403c61fd8527de051738091977b1a0f55d8f57a3169cd7639bfc7c12b76bfed1d181bb0f11703a856662ec9881c12d9161f6dcd2ee93944ffea91242d44fec60000012800000090a6cb4dd88ac92c6b5a4ae82cff87a044045c77a4e80de3f32ce26ba215af37a5920a6e79856482ebd39412f0d73b21e75f2574174551ef064542443ef442e1ddde8f12b68b7bc0e28b909fe9ca47d5f3073052dcf8f09ce065411cb8ba32f0926086fa4cbad904ff65e0da12786c75962f0c3c81a6944482ad6dd62325eb510876b2344cf716251d66823571f2e0274100000090da4265c0f5bfc4912d2f6f66050f31edf4a5f8ae595fe31ab51a35a3786f58cec20f6b97b1309f7101e61271d5eb76c3c8c8ebba1f7123f5a3ab04b8608dea8c3df4710c1786780a991f79abc53df3221ecb47d0e156cca39321e87aa4951b9a19af3e7985062804d04b5d16d1751412294bf8c83c6f5b3ac8eeeb0f6a4ca65d9bc3535d615f5f7182c68065bcc39fe50000012800000090fb469fd753fe55cbfd9ac2799ae0586fecc59bb64a6757807b0013891f789edbb40550a4b53daba336134b4c28d820e43b15d0eee58b4e2d7668246e43e085e091c1a7245d3a678cf3dc06c71bead785096fbd71e8b7703393f52ac5ab280dc887d79def6236fa83e9a54be8f9d556901106966b3796ae00aea8268bd341a46281c32c83b2d4efc8a4350e730e2ea3c900000090e4b3c0f78e9760ab8f74df524b55e7f78b11d938d0dd2752345c54fa0e74fc7e6e74e9d97183e155f86af071fe3dde95a3f19a890d72b70c8aba0a447e291877893d6dbba7530a166d124af687d2147d01977a67e131e722a2578799bfee53455b46cdc55ebd5bc8d566beab804c59f3210fc30f643d8e34ab4960a3baaa38b952c6c1dadda7b9b74322fbbaff936ab400000128000000906fd52dcb60a123a8ed6dd6f7a30a42dcbd065573c6ca3e98eea05d4e1b65fdbc40c0821edb433bc2d8655d5a08055902257b6445f8608de205a55a74400612c492358846019ce6c3af9634a800baf2f80cadf3fc72a45d8c3ee52d54f3df98a9298ce463756601e07997356e003742102d7b89fd272b55ff22078112f528c5868a9204e40af4c4d7fca3335792fcd53100000090ccf2297312528133d9f60d444b9b8b119078a2af1609486e807be9908d7061a0ccc7445301037ba20f54f3ec8ada23c0118a0465c6fbaad5c37a87080739b5286326fc1c63c5b5f5be4ffa005078fa2f24caa4bebf29cb5f2639f54f0a844b66ea43b1a1f2bb61ecffb8dd2e4f02d67b14582e7e31867805b3bcaa1fa4a576e9b95ed1b3539d0eeca3c790d5c6dd2ee80000012800000090081ece26e8f76b59a447c34becb1f732b580cc5a15a50b6a6426baa49d4fc2dc64f0d448747936770a17443af8c026b3286bf6b0c6c594725468202d699563b2754636a51822ee45cd65808f4d22a5800d7bd45cb173886ad46fc91ab0d69ccfe99a8ecf8503e9db0d26b0518b084fea01fc820b701c5299fe3f2a49f354fa3f8c5ccd9182ada3920237e3a9ed00ab4d0000009007282cc8ccd29a3ce10e7c15fc92904bb443eaac26a2aa2f0f680cebe5086b524ced8ffcc73973abddd916b5163a510e122d5900831d0e861f8103e9c10d599c1f7ca16371fbc216049c978f8950cf4804ef4d328b2a43be83812b29a16200492a03a15bfe3798400fd70cae8b6a73e90e56f6d2a7e67e3b2b2c50c9995d67e4fe82e3177829d2f6665311b4e4e5f84900000128000000902922be583917dbcd5588e6afefd4b7f0dbcf3965e2edb2dac9818ac51671fbd248590000bedf44a27d7a5c422487c24ca628ee01d54ff46530b1d32ed2f91f75edccebdf66799fcb1498d44549f22846044c84da9fb0768659f64c453dfd035aa3201bff0e6f3f1e6c962c8ac733865220b0ef797cc1298b54ebc1720fb1c33065567afc98c4aa83ca98ecfbbee52b8800000090a40a7b8173ecfd1ebb9019a5bf79b7a42401b155beb54b3b5ed4589304bffa9f88ef57a7c2c93692e1a12694c29d7b62ee4dbc186ea8f7c6a4d880968b825793987f492c6068dc5a3eeebf75c39366eb267741a2879fc1341a1f2d094e36cdf0c4ce17475b7154c724793fb3a7994755050d913e1fc6d7a8ccef65f8219976c1fcdcd752813cfe9e05abb092fe31fd7100000ce4000001280000009029f8f1801b08438bac7ac5ad3e41010ea0919347b78b2f5162eaea9f6bd5d6290e02e5ab66b8e9120e383b1d9fb3b2723278b144a677309765b73543b26fcbc3a1b870078585dca069cd21c03acc344b0d4e3ca66a292511d0c29410528808a1fe77af633f7fb12818aa63d6a948ea380dfe2555136860750e848afa63fb047fadf862af7ce143de5ba7146118fb608e000000907f3284a85b27b591aa3f1c2fb7f308ffe34991dcaae4fdb769ec9203f7bf158125113ebfe2e65bb92e87636bd5a0793de72aba6ea22bdc1dc4ae6f928299ce6349b266fd480613ff530bf0dd743920f206d7af03327f90b18aa1406b9ea33ca2c360773c5d470faeb666343abe11fa7e23557b7ed2dc1a7e22c5d68df018a76a582b988c1bcad30fc612ffb62228a44d00000128000000900b0bf3b70b7a7d2f881fa7add0e8d380f96cd7bcf262db94a01a7a42772b3ead87c9b8499e9ed4ce2a5eac89398554a2d2fd2570d2fdda66cedd4ef0bfce1868be6c2343ee8fa590fafdb0d9437ed4aa0d5898872d5d9b758b6e5bf7aa005e1d17161d05e0e3de3ba63ad7594c976b48125977eaef362062e9017a469d42783c7f277e062cb8d75f0689a259596d330d0000009089d61159fc62832abec43154658068ac119f084063ec2ccabbb8e426cb4cfaf1521de619429769d9ce4f43087a7e336cf8bfe6f17fe81d8f50a808edce08da742c169fcd4ebc8d438f649c281c95b7962cc69f1dce321e0e77e233b61d6e803d94440601bae7096ada998978fa149aac24c64006b7e3e5e430bf4414b7b2098f8e08bedaf2958442bc904bf443def19e00000128000000904821df25a9d5ab2a80347092baa117d3c44de780feb4cf4525839d25884401c089acdd90034ad633ee118ca180ab5effe53c57f184ed09373f1c5a54d66c91b1c677ec8f7623da96b3f48711f96daed204bdb25dc4b5ae50b0b39f71c18c4fba026a32989160f68a90e888ca876a01950392a8d3f18f27ce104cb30be5992107f6ce3887e3422f08d5b8e54338fa63d200000090d2d6f0ab132b230833a285db79c37146eefb31e6a42f109be1c97ddb15cdfbd55b210bfa5b69d7af8b441f718cec0665506ddb9ae0895b25bc80b3e0734367cf0eb7cbb43de244296ad7738f6388e3361b2442d8392e5131ff6651f2975640f461f0acb66f4e81c1a6f71bee32e747360899adb66ef52e2f7e10e927f79fb6e3cc14cc6c197e4e9a622cbd5a80a6dc010000012800000090c25f7b6097a0b3a4c46643aa5975f8e11fe29aae080c78426ca72a8aa619f9c03c8d63347c727b839e09a8e72d0ec75ba02cf9a5b409ada4efccc4725cc86d088ada592f8f1cdb988f26ca3dfba7cbec040ef0d79ce722f4151581d51b5a63b1a7343f4289eb3690f060927cd897e8f70913099077a87c9e160ff38eece4cef5d789ea0c00c26e3bb1a77587ce0338fa00000090825b7dd50fb89d8c6ba6326d596a5c06c5842d482cacc1c1d7a122c4ec3bd1c1cf180af508bd7bf33ae65342fdc3ad24f1ae4680836ed9de868a7597711073bddb5a9af6b58b5595d524f312ebac882c2f1edb96fa6e20f5b4b57944149d74bae8906265cdba49e7467c361022457030093c1b1af15b56ed2f5e05b61dde42826ef9ae231b0fe3e1e8fe6173c723684a00000128000000901031042419b5589176350e157c7ca4c35f2f56a9877aea2f6ae784a9389a6b22e0a9146c2fe513d361c5bd4b4c67b1acd3e3008df27ec2bdbc7babf2a44763e5c4aa6d4c0a67c1d2f838d1b8c80ded80068d561c2715dcdd9e64eb877d62cbe65fce422ba572143f1c60ec63cb7e266e10228516534d2ebb44a8c9d1580f7786979ef445bf14f99d303d62cd3bd82fe400000090457a32df3cdb8659103dfa373db347be0cda534b0caad190e22e39941f326568116005c076a7074958f1e830123ecd2fce7f13039917fb09e14d84cf1c9f91bebdf79ac7baf4f8fff44a1e7476c40b7e2e8390d4d4013327632c0ac84d795248238650c7825335cdeb6da45e67c0f290047dae6437e45190ea1f946a1ac6cb6d52531f3507c6dae6a49784178bc2ac2900000128000000901d9280e1a8a4b914c29221cc1c4941bc6b4453e7bcb63497882b9d3f0001527690057d786c35371f395a53d1e6b1b9b06d1276f949472dd31d3eae18cfbaa3ab69442c89e547f59640e790e1be821dec296f42b90457bdb1e4b721e81c8b514abaf3dc28e382e683d103bb11c1d513ba2eaa710297078adf24adebc75972b8045784a8c3c403316596840a4358b16db700000090eccbb7543f80e1e70bee5afa8086f659aa515db8b515cf8bddb306db56bcf9274092aa5d320d85a31d27208dfce834c3c9268e6239921824bdfbbd03f8024d42bc67b7eb2e7db7b8bc8bae88e210db0a0fb70ac9ef9838d8c4395cdf197a7eedfa0e860d7d3f310da091e918dcb77d4f1b89afbaa6eeb33b3a92764929a866c8ae994a5537b9ac7d4633d931b7957e070000012800000090c71cdcf61db3a86ea5eced6aca4ce9a1ffbb066daa2b50f2ca8a61f4732e2b7c96061e68c625600778fdcbd5bcb3beac95394a520e1ed8e033ca59f9210572fef01ba88c9b4d6545768633aee89ceff92b7f081e36cdaf87ce465ff682899579e9b5e6f44236856f3f59ccae77ab35c703008665a71bc22dce3ae6fbac421e347a57e30590816eb1d67124d2976eace8000000904ddf9ee90c64e88ce46b9a406ef7b6907e57512a430c8eb16b7a4ed676ff47800a4582f515773a800476a1198adb500671a953bd614e379f2f467d635e886cf8ddbd37532de8d7aeec2ebed7758d190c133cb01f06a6baf3e5dc38734994919309134af3f945f3adab99b8fff5f85efd1b2c64089fe9b25c2b42bf0068ad5a3cfa0c191b40bb7fe68966cdcf66e57c8d00000128000000901c86a2cdd1a95ce50d2f0f68b018c5b04f4e25f51611af0c8f963e8d35c812a26e38fa9cee19470fa4c54a925e4ff54d0dbb9eaeaf922dec84c4828815f39e86804a0d79739039653830b1e17d7e3305229d76b5c71a91c9644d9696322b6214213eb3451af86b0b593f535f8ba0d8ee0beb6bcc713d0b05a28c59aa10f0afb86940d708e3fa8176adda2adcc76f4527000000903da13163fe971c6fffdce5178025b41f068b33629e018751e71e15f2fb27dadef3eaba55a335c2ecc103a415379d8d900cf37b77e27821ca7c14afa7a3a789f125d5b09e2f2736e728653a97723467c524e4fef30f912f431960805f255743794fd1629fb6aaeeae22e987a4245f8dce1e46a9242e12e381bbfee1265301f2ca098b1bc64e0870c29b1fe6231ee1f1b40000012800000090a55ba558c0e0cde27b03fa4a8a134787406573e2807a5fc046ed34850471950442b984f0d3dea8c184b47bb8d84185135c15c165c4ff4af27dd288c8ba2f74a7331140285b79a0fa966aec4c37a6c1e5074a9f2812af9b5dd097bbe80e6a461b621d14ffba1d53eee9d2a1113d72bf881c834913596665572551b672fb3d6e4c4d0c0345b577d8ffc442e7014734961c0000009015b74fa91dadcd8c594fea88ef79e8cd490a08c24fa2817d074d44290fd49675918b21cafb38f20e220023df6e78a787437497746256eb236a2ac5d68197100d619743557dd878e300bc3a6d1d5f369807b6485806595efb40abf8c7764b1389b1d7bf301343a52213ab75f4370958252bfd6ac6b063da88cc12f79b6c1934f01606d8bcafbf28eeeec0eff0cc8c1a2b00000128000000905122ffbaef9c6215a621fcc6e934044dd1eeabb5e6c6b79b575f3a5ce9b36aa91b64d7c884ab712351bd86da2bcf038bb00ef678e9b93add069d3870c20c33f083e924589110bb165a7709ccc3b345912096b93e48f3e9235701b569cf5b98a2ed2304f7b53a4d76df686fa5d50b84442169bd2fc22498fd3c749c3dd6fce714cd6e4f716b33a0d7ea75125ce89971b700000090d6bf3663a143c50be87157b51a4ca02570269d188ee4b4659d1883b876c31738fb5c962ecf61989850d6811aaa6449282163d7507dece75518f2d775979825b5ec63e774ef9eb937d51329189c774ca42e597daeaa8167099320ea3bb56fd604c61d70b16f9caf1daeefed9e77d52abc1374e133c74323b3a1338c66841dc38edf47ec04d8051980a207dfcabd7bc3c200000128000000906d77b45867b311877cf71562af663ecb92898916ea2da7892f0c8abd85cd89566b7d43d907b04c89ece3fc6917bb33810749a9f48375c2000f59cb28511a0562ee5dbd60f593f41fbafe578d4953e9232870448c5d3da0fac9c2e187edab1e869200e6254de8c755667f719ac60c7ba82e41de397cbb95838f92bd34eec638e4ff0fa73dd00f53cab3f1e6a661d51b8d0000009046933696675840166383ebc5a6649df5f10c2197eb973216713c29d847df7949217c25078e45cbc4add112732f10f2cb999790e86eb321ec8e5e0fe69e56e2fc24cb72bd2ab6e7b3cebe194c52a3a1160c8dd38782749751358e6a6e9d4778e7b816cc3c12e806d91d88cea2d097b85e25e55c8b1fab1016ef494b775e6b4f0f1c92a9cfdffbea8f6f74feb460b613f3", + "calldataHash": "0x1b76574a5ac7ec6cae194cea8d01f60b739f2696b2a1b0e70d32d93eab527605", "decodedHeader": { - "bodyHash": "0x484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c1258286", + "bodyHash": "0x1b76574a5ac7ec6cae194cea8d01f60b739f2696b2a1b0e70d32d93eab527605", "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1706272843, - "version": 1 + "timestamp": 1707224952, + "version": 1, + "coinbase": "0xdfbe2253407dbd0a152c036a2ed1237465c243c6", + "feeRecipient": "0x1cc1690e2bfa2c49ad640289205cb9547e1fdffff97848aab22d8a541ec3b9d8" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c41810907" + "root": "0x25363e47eb431704f0a4b33fae75effc7c34f2591315970bc9b3adaefd5780fc" }, "stateReference": { "l1ToL2MessageTree": { @@ -92,8 +94,8 @@ } } }, - "header": "0x1f1de772c009f5b1660876343eb57b7a676a84c695b0c526de2f238c4181090700000002484df1f693f6fe8712cc9129413652b277db358ece78850f1073d963c125828606c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e00000280022612683c6c4a0955c8248d409bc8ec8776d96a3bfe5b5a7e76e492a4f26cb000000008039e689049f104493f0e819b00d874663f0724639f854b8722e8ee829b0f136a000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065b3a84b", + "header": "0x25363e47eb431704f0a4b33fae75effc7c34f2591315970bc9b3adaefd5780fc000000021b76574a5ac7ec6cae194cea8d01f60b739f2696b2a1b0e70d32d93eab52760506c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b0000002024c6dc6d357aad01e10fe1adb877bb28b1df97375b874116e488086ca76e5f9600000200268020a622156e2beac47431b0cd70e1c81fef9a6aa3c365bfcbed9aa7301c5e00000280022612683c6c4a0955c8248d409bc8ec8776d96a3bfe5b5a7e76e492a4f26cb000000008039e689049f104493f0e819b00d874663f0724639f854b8722e8ee829b0f136a000000a00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065c22f78dfbe2253407dbd0a152c036a2ed1237465c243c61cc1690e2bfa2c49ad640289205cb9547e1fdffff97848aab22d8a541ec3b9d8", "l1ToL2MessagesHash": "0xa10cc8559615be5a44cfb608374b1f84fd11cdb5844ebffafd92a77c068350f1", - "publicInputsHash": "0x2cbde160e7af7c59ad9714ca77d07e5dca90aa6016d28e7939e201190b06740c" + "publicInputsHash": "0x10f0d0db33d66808e557ea29c2325e0154f8c75ce15dc93ed12799143b5c8720" } } \ No newline at end of file diff --git a/l1-contracts/test/merkle/Merkle.t.sol b/l1-contracts/test/merkle/Merkle.t.sol new file mode 100644 index 00000000000..f430b72e43f --- /dev/null +++ b/l1-contracts/test/merkle/Merkle.t.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {NaiveMerkle} from "./Naive.sol"; +import {FrontierMerkle} from "./../../src/core/messagebridge/frontier_tree/Frontier.sol"; + +contract MerkleTest is Test { + NaiveMerkle internal merkle; + FrontierMerkle internal frontier; + + uint256 public constant DEPTH = 10; + + function setUp() public { + merkle = new NaiveMerkle(DEPTH); + frontier = new FrontierMerkle(DEPTH); + } + + function testFrontier() public { + uint256 upper = frontier.SIZE(); + for (uint256 i = 0; i < upper; i++) { + bytes32 leaf = sha256(abi.encode(i + 1)); + merkle.insertLeaf(leaf); + frontier.insertLeaf(leaf); + assertEq(merkle.computeRoot(), frontier.root(), "Frontier Roots should be equal"); + } + } +} diff --git a/l1-contracts/test/merkle/Naive.sol b/l1-contracts/test/merkle/Naive.sol new file mode 100644 index 00000000000..1e6bc9c5584 --- /dev/null +++ b/l1-contracts/test/merkle/Naive.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +contract NaiveMerkle { + uint256 public immutable DEPTH; + uint256 public immutable SIZE; + + uint256 public nextIndex = 0; + + mapping(uint256 index => bytes32 leaf) public leafs; + + constructor(uint256 _depth) { + DEPTH = _depth; + SIZE = 2 ** _depth; + } + + function insertLeaf(bytes32 _leaf) public { + leafs[nextIndex++] = _leaf; + } + + function computeRoot() public view returns (bytes32) { + bytes32[] memory nodes = new bytes32[](SIZE / 2); + uint256 size = SIZE; + for (uint256 i = 0; i < DEPTH; i++) { + for (uint256 j = 0; j < size; j += 2) { + if (i == 0) { + nodes[j / 2] = sha256(bytes.concat(leafs[j], leafs[j + 1])); + } else { + nodes[j / 2] = sha256(bytes.concat(nodes[j], nodes[j + 1])); + } + } + size /= 2; + } + return nodes[0]; + } +} diff --git a/noir/.gitrepo b/noir/.gitrepo index aa2ef42f98f..f725a01b89b 100644 --- a/noir/.gitrepo +++ b/noir/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/noir-lang/noir branch = aztec-packages - commit = 9a70040211d205f472aa31924649c2fef999eb49 - parent = 9c965a7c9e652dfeaba2f09152e5db287407473d + commit = f1b91511124df89bbe9e059b87536901bdf0d6f3 + parent = f5be1f17beeded5ab1ac59331bd520787b3778a1 method = merge cmdver = 0.4.6 diff --git a/noir/Cargo.lock b/noir/Cargo.lock index 93f1d25fc76..291ac30336c 100644 --- a/noir/Cargo.lock +++ b/noir/Cargo.lock @@ -418,6 +418,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" name = "aztec_macros" version = "0.23.0" dependencies = [ + "convert_case 0.6.0", "iter-extended", "noirc_frontend", ] @@ -1003,6 +1004,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -1368,7 +1378,7 @@ version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "convert_case", + "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version", diff --git a/noir/acvm-repo/acir/codegen/acir.cpp b/noir/acvm-repo/acir/codegen/acir.cpp index bdee08794e6..3ce63ecfa94 100644 --- a/noir/acvm-repo/acir/codegen/acir.cpp +++ b/noir/acvm-repo/acir/codegen/acir.cpp @@ -5,65 +5,172 @@ namespace Circuit { - struct Witness { - uint32_t value; + struct BinaryFieldOp { - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); - }; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const FunctionInput&, const FunctionInput&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; + + struct Div { + friend bool operator==(const Div&, const Div&); + std::vector bincodeSerialize() const; + static Div bincodeDeserialize(std::vector); + }; + + struct Equals { + friend bool operator==(const Equals&, const Equals&); + std::vector bincodeSerialize() const; + static Equals bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct BlackBoxFuncCall { + struct BinaryIntOp { - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - friend bool operator==(const AND&, const AND&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; - friend bool operator==(const XOR&, const XOR&); + struct SignedDiv { + friend bool operator==(const SignedDiv&, const SignedDiv&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static SignedDiv bincodeDeserialize(std::vector); }; - struct RANGE { - Circuit::FunctionInput input; + struct UnsignedDiv { + friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + std::vector bincodeSerialize() const; + static UnsignedDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const RANGE&, const RANGE&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; - friend bool operator==(const SHA256&, const SHA256&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); + }; + + struct And { + friend bool operator==(const And&, const And&); + std::vector bincodeSerialize() const; + static And bincodeDeserialize(std::vector); + }; + + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; + + struct Xor { + friend bool operator==(const Xor&, const Xor&); + std::vector bincodeSerialize() const; + static Xor bincodeDeserialize(std::vector); + }; + + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; + + struct Shr { + friend bool operator==(const Shr&, const Shr&); + std::vector bincodeSerialize() const; + static Shr bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); + }; + + struct MemoryAddress { + uint64_t value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); + std::vector bincodeSerialize() const; + static MemoryAddress bincodeDeserialize(std::vector); + }; + + struct HeapArray { + Circuit::MemoryAddress pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; + + struct HeapVector { + Circuit::MemoryAddress pointer; + Circuit::MemoryAddress size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; + + struct BlackBoxOp { + + struct Sha256 { + Circuit::HeapVector message; + Circuit::HeapArray output; + + friend bool operator==(const Sha256&, const Sha256&); + std::vector bincodeSerialize() const; + static Sha256 bincodeDeserialize(std::vector); }; struct Blake2s { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -71,52 +178,38 @@ namespace Circuit { }; struct Blake3 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); - std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); - }; - - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct Keccak256 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; + struct Keccakf1600 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -124,102 +217,95 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); - std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); - }; - - struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + struct SchnorrVerify { + Circuit::MemoryAddress public_key_x; + Circuit::MemoryAddress public_key_y; + Circuit::HeapVector message; + Circuit::HeapVector signature; + Circuit::MemoryAddress result; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - std::vector outputs; + struct PedersenCommitment { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::HeapArray output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::MemoryAddress output; - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + struct FixedBaseScalarMul { + Circuit::MemoryAddress low; + Circuit::MemoryAddress high; + Circuit::HeapArray result; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + struct EmbeddedCurveAdd { + Circuit::MemoryAddress input1_x; + Circuit::MemoryAddress input1_y; + Circuit::MemoryAddress input2_x; + Circuit::MemoryAddress input2_y; + Circuit::HeapArray result; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct BigIntSub { + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -227,9 +313,9 @@ namespace Circuit { }; struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -237,9 +323,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + Circuit::HeapVector inputs; + Circuit::HeapVector modulus; + Circuit::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -247,637 +333,606 @@ namespace Circuit { }; struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + Circuit::MemoryAddress input; + Circuit::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; - + struct Poseidon2Permutation { + Circuit::HeapVector message; + Circuit::HeapArray output; + Circuit::MemoryAddress len; + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; static Poseidon2Permutation bincodeDeserialize(std::vector); }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; + std::variant value; - friend bool operator==(const Expression&, const Expression&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct BrilligInputs { + struct HeapValueType; - struct Single { - Circuit::Expression value; + struct HeapValueType { - friend bool operator==(const Single&, const Single&); + struct Simple { + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; struct Array { - std::vector value; + std::vector value_types; + uint64_t size; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; static Array bincodeDeserialize(std::vector); }; - std::variant value; + struct Vector { + std::vector value_types; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const Vector&, const Vector&); + std::vector bincodeSerialize() const; + static Vector bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const HeapValueType&, const HeapValueType&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static HeapValueType bincodeDeserialize(std::vector); }; - struct BinaryFieldOp { + struct Value { + std::string inner; - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + friend bool operator==(const Value&, const Value&); + std::vector bincodeSerialize() const; + static Value bincodeDeserialize(std::vector); + }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); - std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); - }; + struct ValueOrArray { - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct MemoryAddress { + Circuit::MemoryAddress value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct HeapArray { + Circuit::HeapArray value; + + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct HeapVector { + Circuit::HeapVector value; + + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const ValueOrArray&, const ValueOrArray&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static ValueOrArray bincodeDeserialize(std::vector); }; - struct BinaryIntOp { + struct BrilligOpcode { - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + struct BinaryFieldOp { + Circuit::MemoryAddress destination; + Circuit::BinaryFieldOp op; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); - std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); - }; + struct BinaryIntOp { + Circuit::MemoryAddress destination; + Circuit::BinaryIntOp op; + uint32_t bit_size; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); - std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); - }; + struct Cast { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; + uint32_t bit_size; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + friend bool operator==(const Cast&, const Cast&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Cast bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); - std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); - }; + struct JumpIfNot { + Circuit::MemoryAddress condition; + uint64_t location; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); - std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); - }; + struct JumpIf { + Circuit::MemoryAddress condition; + uint64_t location; - struct Or { - friend bool operator==(const Or&, const Or&); + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); - std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); - }; + struct Jump { + uint64_t location; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct CalldataCopy { + Circuit::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; + + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; - - struct MemoryAddress { - uint64_t value; - - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; - - struct HeapArray { - Circuit::MemoryAddress pointer; - uint64_t size; - - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; - - struct HeapVector { - Circuit::MemoryAddress pointer; - Circuit::MemoryAddress size; - - friend bool operator==(const HeapVector&, const HeapVector&); - std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); - }; + struct Call { + uint64_t location; - struct BlackBoxOp { + friend bool operator==(const Call&, const Call&); + std::vector bincodeSerialize() const; + static Call bincodeDeserialize(std::vector); + }; - struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct Const { + Circuit::MemoryAddress destination; + uint32_t bit_size; + Circuit::Value value; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; - - friend bool operator==(const Blake2s&, const Blake2s&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct Mov { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct Load { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source_pointer; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + struct Store { + Circuit::MemoryAddress destination_pointer; + Circuit::MemoryAddress source; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + struct BlackBox { + Circuit::BlackBoxOp value; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static BlackBox bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::MemoryAddress public_key_x; - Circuit::MemoryAddress public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::MemoryAddress result; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct Trap { + friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static Trap bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::HeapArray output; + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const Stop&, const Stop&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Stop bincodeDeserialize(std::vector); }; - struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::MemoryAddress output; + std::variant value; - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + std::vector bincodeSerialize() const; + static BrilligOpcode bincodeDeserialize(std::vector); + }; - struct FixedBaseScalarMul { - Circuit::MemoryAddress low; - Circuit::MemoryAddress high; - Circuit::HeapArray result; + struct Witness { + uint32_t value; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; + + friend bool operator==(const FunctionInput&, const FunctionInput&); + std::vector bincodeSerialize() const; + static FunctionInput bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::MemoryAddress input1_x; - Circuit::MemoryAddress input1_y; - Circuit::MemoryAddress input2_x; - Circuit::MemoryAddress input2_y; - Circuit::HeapArray result; + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static XOR bincodeDeserialize(std::vector); }; - struct BigIntAdd { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct RANGE { + Circuit::FunctionInput input; - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static RANGE bincodeDeserialize(std::vector); }; - struct BigIntNeg { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct SHA256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static SHA256 bincodeDeserialize(std::vector); }; - struct BigIntMul { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct Blake2s { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BigIntMul&, const BigIntMul&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct BigIntDiv { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct Blake3 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::MemoryAddress output; + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - Circuit::MemoryAddress input; - Circuit::HeapVector output; + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::MemoryAddress len; + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + struct EcdsaSecp256k1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); - std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); - }; + struct EcdsaSecp256r1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; - struct Value { - std::string inner; + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256r1 bincodeDeserialize(std::vector); + }; - friend bool operator==(const Value&, const Value&); - std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); - }; + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; - struct ValueOrArray { + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; - struct MemoryAddress { - Circuit::MemoryAddress value; + struct EmbeddedCurveAdd { + Circuit::FunctionInput input1_x; + Circuit::FunctionInput input1_y; + Circuit::FunctionInput input2_x; + Circuit::FunctionInput input2_y; + std::array outputs; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct HeapArray { - Circuit::HeapArray value; + struct Keccak256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::HeapVector value; + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const ValueOrArray&, const ValueOrArray&); - std::vector bincodeSerialize() const; - static ValueOrArray bincodeDeserialize(std::vector); - }; - - struct BrilligOpcode { - - struct BinaryFieldOp { - Circuit::MemoryAddress destination; - Circuit::BinaryFieldOp op; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Circuit::MemoryAddress destination; - Circuit::BinaryIntOp op; - uint32_t bit_size; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::FunctionInput key_hash; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static RecursiveAggregation bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Circuit::MemoryAddress condition; - uint64_t location; + struct BigIntAdd { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct JumpIf { - Circuit::MemoryAddress condition; - uint64_t location; + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; - struct Jump { - uint64_t location; + struct BigIntMul { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const Jump&, const Jump&); + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct CalldataCopy { - Circuit::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; + struct BigIntDiv { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const CalldataCopy&, const CalldataCopy&); + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - struct Call { - uint64_t location; + struct BigIntFromLeBytes { + std::vector inputs; + std::vector modulus; + uint32_t output; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static BigIntFromLeBytes bincodeDeserialize(std::vector); }; - struct Const { - Circuit::MemoryAddress destination; - Circuit::Value value; + struct BigIntToLeBytes { + uint32_t input; + std::vector outputs; - friend bool operator==(const Const&, const Const&); + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); + static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Return { - friend bool operator==(const Return&, const Return&); + struct Poseidon2Permutation { + std::vector inputs; + std::vector outputs; + uint32_t len; + + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); + static Poseidon2Permutation bincodeDeserialize(std::vector); }; - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector inputs; + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; - friend bool operator==(const ForeignCall&, const ForeignCall&); + friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); + static Sha256Compression bincodeDeserialize(std::vector); }; - struct Mov { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; + std::variant value; - friend bool operator==(const Mov&, const Mov&); - std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); - }; + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); + std::vector bincodeSerialize() const; + static BlackBoxFuncCall bincodeDeserialize(std::vector); + }; - struct Load { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source_pointer; + struct BlockId { + uint32_t value; - friend bool operator==(const Load&, const Load&); - std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); - }; + friend bool operator==(const BlockId&, const BlockId&); + std::vector bincodeSerialize() const; + static BlockId bincodeDeserialize(std::vector); + }; - struct Store { - Circuit::MemoryAddress destination_pointer; - Circuit::MemoryAddress source; + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - friend bool operator==(const Store&, const Store&); - std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); - }; + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; - struct BlackBox { - Circuit::BlackBoxOp value; + struct BrilligInputs { - friend bool operator==(const BlackBox&, const BlackBox&); + struct Single { + Circuit::Expression value; + + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct Trap { - friend bool operator==(const Trap&, const Trap&); + struct Array { + std::vector value; + + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; + struct MemoryArray { + Circuit::BlockId value; - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + friend bool operator==(const BrilligInputs&, const BrilligInputs&); std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); + static BrilligInputs bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -1016,6 +1071,29 @@ namespace Circuit { static Opcode bincodeDeserialize(std::vector); }; + struct ExpressionWidth { + + struct Unbounded { + friend bool operator==(const Unbounded&, const Unbounded&); + std::vector bincodeSerialize() const; + static Unbounded bincodeDeserialize(std::vector); + }; + + struct Bounded { + uint64_t width; + + friend bool operator==(const Bounded&, const Bounded&); + std::vector bincodeSerialize() const; + static Bounded bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ExpressionWidth&, const ExpressionWidth&); + std::vector bincodeSerialize() const; + static ExpressionWidth bincodeDeserialize(std::vector); + }; + struct OpcodeLocation { struct Acir { @@ -1053,6 +1131,7 @@ namespace Circuit { struct Circuit { uint32_t current_witness_index; std::vector opcodes; + Circuit::ExpressionWidth expression_width; std::vector private_parameters; Circuit::PublicInputs public_parameters; Circuit::PublicInputs return_values; @@ -2623,22 +2702,22 @@ Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable BlackBoxFuncCall::BigIntNeg::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntNeg BlackBoxFuncCall::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntSub BlackBoxFuncCall::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2649,7 +2728,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntNeg &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2657,8 +2736,8 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntNeg obj; +Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); @@ -3551,22 +3630,22 @@ Circuit::BlackBoxOp::BigIntAdd serde::Deserializable BlackBoxOp::BigIntNeg::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntNeg BlackBoxOp::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntSub BlackBoxOp::BigIntSub::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -3577,7 +3656,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntNeg &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3585,8 +3664,8 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntNeg obj; +Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); @@ -4029,20 +4108,58 @@ Circuit::BrilligInputs::Single serde::Deserializable BrilligInputs::Array::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BrilligInputs::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Circuit::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::Array obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const BrilligInputs::MemoryArray &lhs, const BrilligInputs::MemoryArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BrilligInputs::Array::bincodeSerialize() const { + inline std::vector BrilligInputs::MemoryArray::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector input) { + inline BrilligInputs::MemoryArray BrilligInputs::MemoryArray::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -4053,14 +4170,14 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Array &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::Array obj; +Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::MemoryArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4204,6 +4321,50 @@ Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable BrilligOpcode::Cast::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BrilligOpcode::Cast BrilligOpcode::Cast::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BrilligOpcode::Cast &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); +} + +template <> +template +Circuit::BrilligOpcode::Cast serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligOpcode::Cast obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BrilligOpcode::JumpIfNot &lhs, const BrilligOpcode::JumpIfNot &rhs) { @@ -4410,6 +4571,7 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::Const &lhs, const BrilligOpcode::Const &rhs) { if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.bit_size == rhs.bit_size)) { return false; } if (!(lhs.value == rhs.value)) { return false; } return true; } @@ -4435,6 +4597,7 @@ template <> template void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); serde::Serializable::serialize(obj.value, serializer); } @@ -4443,6 +4606,7 @@ template Circuit::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { Circuit::BrilligOpcode::Const obj; obj.destination = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4487,7 +4651,9 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { if (!(lhs.function == rhs.function)) { return false; } if (!(lhs.destinations == rhs.destinations)) { return false; } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { return false; } if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } @@ -4513,7 +4679,9 @@ template void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.function, serializer); serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> @@ -4522,7 +4690,9 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4886,6 +5056,7 @@ namespace Circuit { inline bool operator==(const Circuit &lhs, const Circuit &rhs) { if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } if (!(lhs.opcodes == rhs.opcodes)) { return false; } + if (!(lhs.expression_width == rhs.expression_width)) { return false; } if (!(lhs.private_parameters == rhs.private_parameters)) { return false; } if (!(lhs.public_parameters == rhs.public_parameters)) { return false; } if (!(lhs.return_values == rhs.return_values)) { return false; } @@ -4917,6 +5088,7 @@ void serde::Serializable::serialize(const Circuit::Circuit &ob serializer.increase_container_depth(); serde::Serializable::serialize(obj.current_witness_index, serializer); serde::Serializable::serialize(obj.opcodes, serializer); + serde::Serializable::serialize(obj.expression_width, serializer); serde::Serializable::serialize(obj.private_parameters, serializer); serde::Serializable::serialize(obj.public_parameters, serializer); serde::Serializable::serialize(obj.return_values, serializer); @@ -4932,6 +5104,7 @@ Circuit::Circuit serde::Deserializable::deserialize(Deserializ Circuit::Circuit obj; obj.current_witness_index = serde::Deserializable::deserialize(deserializer); obj.opcodes = serde::Deserializable::deserialize(deserializer); + obj.expression_width = serde::Deserializable::deserialize(deserializer); obj.private_parameters = serde::Deserializable::deserialize(deserializer); obj.public_parameters = serde::Deserializable::deserialize(deserializer); obj.return_values = serde::Deserializable::deserialize(deserializer); @@ -5122,6 +5295,121 @@ Circuit::Expression serde::Deserializable::deserialize(Dese return obj; } +namespace Circuit { + + inline bool operator==(const ExpressionWidth &lhs, const ExpressionWidth &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector ExpressionWidth::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth ExpressionWidth::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::ExpressionWidth obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const ExpressionWidth::Unbounded &lhs, const ExpressionWidth::Unbounded &rhs) { + return true; + } + + inline std::vector ExpressionWidth::Unbounded::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth::Unbounded ExpressionWidth::Unbounded::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded &obj, Serializer &serializer) { +} + +template <> +template +Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Unbounded obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const ExpressionWidth::Bounded &lhs, const ExpressionWidth::Bounded &rhs) { + if (!(lhs.width == rhs.width)) { return false; } + return true; + } + + inline std::vector ExpressionWidth::Bounded::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth::Bounded ExpressionWidth::Bounded::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.width, serializer); +} + +template <> +template +Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Bounded obj; + obj.width = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const FunctionInput &lhs, const FunctionInput &rhs) { @@ -5212,6 +5500,162 @@ Circuit::HeapArray serde::Deserializable::deserialize(Deseri return obj; } +namespace Circuit { + + inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector HeapValueType::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + return true; + } + + inline std::vector HeapValueType::Simple::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { +} + +template <> +template +Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Simple obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } + return true; + } + + inline std::vector HeapValueType::Array::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); +} + +template <> +template +Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + return true; + } + + inline std::vector HeapValueType::Vector::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); +} + +template <> +template +Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { diff --git a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs index 97b4759d350..0a7ee244a5e 100644 --- a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -50,7 +50,7 @@ pub enum BlackBoxFunc { /// BigInt addition BigIntAdd, /// BigInt subtraction - BigIntNeg, + BigIntSub, /// BigInt multiplication BigIntMul, /// BigInt division @@ -91,7 +91,7 @@ impl BlackBoxFunc { BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", BlackBoxFunc::BigIntAdd => "bigint_add", - BlackBoxFunc::BigIntNeg => "bigint_neg", + BlackBoxFunc::BigIntSub => "bigint_sub", BlackBoxFunc::BigIntMul => "bigint_mul", BlackBoxFunc::BigIntDiv => "bigint_div", BlackBoxFunc::BigIntFromLeBytes => "bigint_from_le_bytes", @@ -120,7 +120,7 @@ impl BlackBoxFunc { "keccakf1600" => Some(BlackBoxFunc::Keccakf1600), "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), "bigint_add" => Some(BlackBoxFunc::BigIntAdd), - "bigint_neg" => Some(BlackBoxFunc::BigIntNeg), + "bigint_sub" => Some(BlackBoxFunc::BigIntSub), "bigint_mul" => Some(BlackBoxFunc::BigIntMul), "bigint_div" => Some(BlackBoxFunc::BigIntDiv), "bigint_from_le_bytes" => Some(BlackBoxFunc::BigIntFromLeBytes), diff --git a/noir/acvm-repo/acir/src/circuit/brillig.rs b/noir/acvm-repo/acir/src/circuit/brillig.rs index 63c6ad2a3d4..f394a46ff82 100644 --- a/noir/acvm-repo/acir/src/circuit/brillig.rs +++ b/noir/acvm-repo/acir/src/circuit/brillig.rs @@ -1,3 +1,4 @@ +use super::opcodes::BlockId; use crate::native_types::{Expression, Witness}; use brillig::Opcode as BrilligOpcode; use serde::{Deserialize, Serialize}; @@ -8,6 +9,7 @@ use serde::{Deserialize, Serialize}; pub enum BrilligInputs { Single(Expression), Array(Vec), + MemoryArray(BlockId), } /// Outputs for the Brillig VM. Once the VM has completed diff --git a/noir/acvm-repo/acir/src/circuit/mod.rs b/noir/acvm-repo/acir/src/circuit/mod.rs index ccfb19bbf05..9cbacdc2ab0 100644 --- a/noir/acvm-repo/acir/src/circuit/mod.rs +++ b/noir/acvm-repo/acir/src/circuit/mod.rs @@ -15,12 +15,30 @@ use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serial use std::collections::BTreeSet; +/// Specifies the maximum width of the expressions which will be constrained. +/// +/// Unbounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports R1CS. +/// +/// Bounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports PLONK, where arithmetic expressions have a +/// finite fan-in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +pub enum ExpressionWidth { + #[default] + Unbounded, + Bounded { + width: usize, + }, +} + #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct Circuit { // current_witness_index is the highest witness index in the circuit. The next witness to be added to this circuit // will take on this value. (The value is cached here as an optimization.) pub current_witness_index: u32, pub opcodes: Vec, + pub expression_width: ExpressionWidth, /// The set of private inputs to the circuit. pub private_parameters: BTreeSet, @@ -240,7 +258,7 @@ mod tests { opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Compression, Opcode, PublicInputs, }; - use crate::native_types::Witness; + use crate::{circuit::ExpressionWidth, native_types::Witness}; use acir_field::FieldElement; fn and_opcode() -> Opcode { @@ -318,6 +336,7 @@ mod tests { fn serialization_roundtrip() { let circuit = Circuit { current_witness_index: 5, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![and_opcode(), range_opcode()], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), @@ -340,6 +359,7 @@ mod tests { fn test_serialize() { let circuit = Circuit { current_witness_index: 0, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![ Opcode::AssertZero(crate::native_types::Expression { mul_terms: vec![], diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index ba4964c8912..f73417a4b5b 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -120,7 +120,7 @@ pub enum BlackBoxFuncCall { rhs: u32, output: u32, }, - BigIntNeg { + BigIntSub { lhs: u32, rhs: u32, output: u32, @@ -193,7 +193,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, BlackBoxFuncCall::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxFuncCall::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxFuncCall::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxFuncCall::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxFuncCall::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, @@ -223,7 +223,7 @@ impl BlackBoxFuncCall { vec![*lhs, *rhs] } BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } | BlackBoxFuncCall::BigIntToLeBytes { .. } => Vec::new(), @@ -328,7 +328,7 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::RecursiveAggregation { .. } | BlackBoxFuncCall::BigIntFromLeBytes { .. } | BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } => { vec![] diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs b/noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs index 9e45dc4ee8c..0e94c0f051e 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs @@ -1,7 +1,7 @@ use crate::native_types::{Expression, Witness}; use serde::{Deserialize, Serialize}; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] pub struct BlockId(pub u32); /// Operation on a block of memory diff --git a/noir/acvm-repo/acir/src/lib.rs b/noir/acvm-repo/acir/src/lib.rs index 0a72cec6070..c7be5026850 100644 --- a/noir/acvm-repo/acir/src/lib.rs +++ b/noir/acvm-repo/acir/src/lib.rs @@ -31,7 +31,10 @@ mod reflection { path::{Path, PathBuf}, }; - use brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, ValueOrArray}; + use brillig::{ + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, + ValueOrArray, + }; use serde_reflection::{Tracer, TracerConfig}; use crate::{ @@ -39,7 +42,7 @@ mod reflection { brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, opcodes::BlackBoxFuncCall, - Circuit, Opcode, OpcodeLocation, + Circuit, ExpressionWidth, Opcode, OpcodeLocation, }, native_types::{Witness, WitnessMap}, }; @@ -57,6 +60,7 @@ mod reflection { let mut tracer = Tracer::new(TracerConfig::default()); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); @@ -68,6 +72,7 @@ mod reflection { tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/noir/acvm-repo/acir/tests/test_program_serialization.rs b/noir/acvm-repo/acir/tests/test_program_serialization.rs index c94c5ae66b0..2c8ad2b9986 100644 --- a/noir/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/acvm-repo/acir/tests/test_program_serialization.rs @@ -20,7 +20,7 @@ use acir::{ native_types::{Expression, Witness}, }; use acir_field::FieldElement; -use brillig::{HeapArray, MemoryAddress, ValueOrArray}; +use brillig::{HeapArray, HeapValueType, MemoryAddress, ValueOrArray}; #[test] fn addition_circuit() { @@ -45,12 +45,12 @@ fn addition_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, - 219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, - 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, 111, 116, 133, 197, 69, 144, 153, 91, - 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173, - 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, - 245, 233, 224, 1, 1, 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, + 182, 94, 165, 166, 122, 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, + 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, 138, 139, 197, 88, 68, 122, 205, 157, 152, + 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, 188, 162, 147, + 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, + 63, 243, 81, 87, 163, 125, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -75,9 +75,9 @@ fn fixed_base_scalar_mul_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, - 163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, - 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, + 209, 247, 229, 130, 130, 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, + 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -102,9 +102,9 @@ fn pedersen_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, - 138, 10, 34, 65, 84, 198, 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, - 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, + 27, 196, 64, 200, 100, 0, 15, 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, + 48, 224, 71, 90, 33, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -143,22 +143,22 @@ fn schnorr_verify_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, - 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, - 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, 193, 19, 142, 243, 183, 255, 14, 179, - 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206, - 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, - 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, - 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, 142, 21, - 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, 223, 142, 241, - 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, - 47, 186, 139, 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, - 138, 126, 162, 157, 232, 38, 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, - 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29, - 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, - 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, - 219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, - 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, + 239, 189, 119, 141, 93, 99, 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, + 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, 234, 219, 204, 146, 239, 91, 170, + 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, 236, + 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, + 115, 156, 231, 2, 23, 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, + 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, 158, 240, 148, 103, 60, 231, 5, 47, 121, + 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, 158, 125, 126, + 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, + 189, 165, 181, 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, + 210, 78, 186, 73, 51, 233, 37, 173, 164, 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, + 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, 235, 236, 156, 141, 179, + 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, + 187, 126, 184, 103, 217, 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, + 239, 128, 225, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -186,7 +186,9 @@ fn simple_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], @@ -204,11 +206,11 @@ fn simple_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 12, 68, 207, 148, 150, 118, - 234, 175, 216, 63, 232, 207, 116, 232, 210, 161, 136, 223, 175, 98, 132, 27, 212, 69, 31, - 132, 28, 23, 8, 119, 59, 0, 131, 204, 66, 154, 41, 222, 173, 219, 142, 113, 153, 121, 191, - 44, 231, 21, 237, 144, 88, 43, 249, 11, 71, 156, 77, 245, 251, 249, 231, 119, 189, 214, - 204, 89, 187, 11, 25, 130, 54, 1, 36, 1, 124, 242, 107, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233, + 212, 79, 177, 127, 208, 159, 233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45, + 119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190, 50, 245, 26, 175, 218, 231, 165, + 57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115, 104, + 181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -258,6 +260,7 @@ fn complex_brillig_foreign_call() { brillig::Opcode::Const { destination: MemoryAddress(0), value: brillig::Value::from(32_usize), + bit_size: 32, }, brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(1), @@ -271,11 +274,20 @@ fn complex_brillig_foreign_call() { ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), ValueOrArray::MemoryAddress(MemoryAddress::from(1)), ], + input_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + ], destinations: vec![ ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), ValueOrArray::MemoryAddress(MemoryAddress::from(35)), ValueOrArray::MemoryAddress(MemoryAddress::from(36)), ], + destination_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + HeapValueType::Simple, + ], }, brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, ], @@ -293,14 +305,15 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 65, 10, 132, 48, 12, 76, 218, 237, 174, 123, - 242, 11, 130, 62, 160, 250, 2, 255, 34, 222, 20, 61, 250, 124, 11, 78, 49, 4, 193, 131, 21, - 52, 16, 210, 132, 105, 50, 77, 210, 140, 136, 152, 54, 177, 65, 13, 206, 12, 95, 74, 196, - 181, 176, 254, 154, 212, 156, 46, 151, 191, 139, 163, 121, 1, 71, 123, 3, 199, 184, 15, 15, - 157, 119, 202, 185, 36, 237, 159, 61, 248, 63, 159, 160, 46, 232, 23, 254, 15, 54, 67, 156, - 96, 11, 213, 119, 82, 248, 116, 179, 104, 188, 163, 125, 15, 89, 213, 253, 139, 154, 221, - 52, 206, 67, 191, 88, 5, 213, 52, 75, 113, 174, 96, 205, 201, 157, 24, 207, 197, 211, 157, - 6, 50, 18, 233, 158, 72, 89, 1, 53, 215, 75, 175, 196, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179, + 154, 35, 8, 51, 7, 232, 204, 9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213, + 141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32, 204, 48, 206, 18, 158, 19, 175, + 37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156, 160, + 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241, + 250, 201, 99, 206, 251, 96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47, + 146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 136, 249, 87, 249, 105, + 231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64, 34, 14, 164, + 69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -332,11 +345,10 @@ fn memory_op_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, - 254, 255, 85, 198, 136, 9, 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, - 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, 148, 156, 203, 121, 89, 86, 13, 215, - 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, 235, 225, - 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, + 253, 167, 178, 144, 2, 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, + 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, 98, 174, 212, 177, 188, 187, 92, 255, + 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, 19, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/acvm-repo/acvm/src/compiler/mod.rs b/noir/acvm-repo/acvm/src/compiler/mod.rs index ccb043914d6..6543c70958b 100644 --- a/noir/acvm-repo/acvm/src/compiler/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/mod.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use acir::circuit::{Circuit, OpcodeLocation}; - -use crate::ExpressionWidth; +use acir::circuit::{Circuit, ExpressionWidth, OpcodeLocation}; // The various passes that we can use over ACIR mod optimizers; diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index ecabd98b3b1..64fe5291cc6 100644 --- a/noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -148,7 +148,7 @@ mod tests { use acir::{ circuit::{ opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, Opcode, PublicInputs, + Circuit, ExpressionWidth, Opcode, PublicInputs, }, native_types::{Expression, Witness}, }; @@ -167,11 +167,13 @@ mod tests { Circuit { current_witness_index: 1, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes, private_parameters: BTreeSet::new(), public_parameters: PublicInputs::default(), return_values: PublicInputs::default(), assert_messages: Default::default(), + recursive: false, } } diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs index e184401c5d4..4be2eb7029e 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -1,12 +1,10 @@ use acir::{ - circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, Opcode}, + circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, ExpressionWidth, Opcode}, native_types::{Expression, Witness}, FieldElement, }; use indexmap::IndexMap; -use crate::ExpressionWidth; - mod csat; mod r1cs; @@ -44,11 +42,11 @@ pub(super) fn transform_internal( acir_opcode_positions: Vec, ) -> (Circuit, Vec) { let mut transformer = match &expression_width { - crate::ExpressionWidth::Unbounded => { + ExpressionWidth::Unbounded => { let transformer = R1CSTransformer::new(acir); return (transformer.transform(), acir_opcode_positions); } - crate::ExpressionWidth::Bounded { width } => { + ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); for value in acir.circuit_arguments() { csat.mark_solvable(value); @@ -159,6 +157,7 @@ pub(super) fn transform_internal( let acir = Circuit { current_witness_index, + expression_width, opcodes: transformed_opcodes, // The transformer does not add new public inputs ..acir diff --git a/noir/acvm-repo/acvm/src/lib.rs b/noir/acvm-repo/acvm/src/lib.rs index 264479d8a12..00a253fde07 100644 --- a/noir/acvm-repo/acvm/src/lib.rs +++ b/noir/acvm-repo/acvm/src/lib.rs @@ -7,7 +7,6 @@ pub mod compiler; pub mod pwg; pub use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -use core::fmt::Debug; use pwg::OpcodeResolutionError; // re-export acir @@ -17,27 +16,3 @@ pub use acir::FieldElement; pub use brillig_vm; // re-export blackbox solver pub use acvm_blackbox_solver as blackbox_solver; - -/// Specifies the maximum width of the expressions which will be constrained. -/// -/// Unbounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports R1CS. -/// -/// Bounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports PLONK, where arithmetic expressions have a -/// finite fan-in. -#[derive(Debug, Clone, Copy)] -pub enum ExpressionWidth { - Unbounded, - Bounded { width: usize }, -} - -impl From for ExpressionWidth { - fn from(width: usize) -> ExpressionWidth { - if width == 0 { - ExpressionWidth::Unbounded - } else { - ExpressionWidth::Bounded { width } - } - } -} diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/bigint.rs b/noir/acvm-repo/acvm/src/pwg/blackbox/bigint.rs new file mode 100644 index 00000000000..986afaa3ce7 --- /dev/null +++ b/noir/acvm-repo/acvm/src/pwg/blackbox/bigint.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; + +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + BlackBoxFunc, FieldElement, +}; + +use num_bigint::BigUint; + +use crate::pwg::OpcodeResolutionError; + +/// Resolve BigInt opcodes by storing BigInt values (and their moduli) by their ID in a HashMap: +/// - When it encounters a bigint operation opcode, it performs the operation on the stored values +/// and store the result using the provided ID. +/// - When it gets a to_bytes opcode, it simply looks up the value and resolves the output witness accordingly. +#[derive(Default)] +pub(crate) struct BigIntSolver { + bigint_id_to_value: HashMap, + bigint_id_to_modulus: HashMap, +} + +impl BigIntSolver { + pub(crate) fn get_bigint( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_value + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + + pub(crate) fn get_modulus( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_modulus + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + pub(crate) fn bigint_from_bytes( + &mut self, + inputs: &[FunctionInput], + modulus: &[u8], + output: u32, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bytes = inputs + .iter() + .map(|input| initial_witness.get(&input.witness).unwrap().to_u128() as u8) + .collect::>(); + let bigint = BigUint::from_bytes_le(&bytes); + self.bigint_id_to_value.insert(output, bigint); + let modulus = BigUint::from_bytes_le(modulus); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } + + pub(crate) fn bigint_to_bytes( + &self, + input: u32, + outputs: &Vec, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bigint = self.get_bigint(input, BlackBoxFunc::BigIntToLeBytes)?; + + let mut bytes = bigint.to_bytes_le(); + while bytes.len() < outputs.len() { + bytes.push(0); + } + bytes.iter().zip(outputs.iter()).for_each(|(byte, output)| { + initial_witness.insert(*output, FieldElement::from(*byte as u128)); + }); + Ok(()) + } + + pub(crate) fn bigint_op( + &mut self, + lhs: u32, + rhs: u32, + output: u32, + func: BlackBoxFunc, + ) -> Result<(), OpcodeResolutionError> { + let modulus = self.get_modulus(lhs, func)?; + let lhs = self.get_bigint(lhs, func)?; + let rhs = self.get_bigint(rhs, func)?; + let mut result = match func { + BlackBoxFunc::BigIntAdd => lhs + rhs, + BlackBoxFunc::BigIntSub => { + if lhs >= rhs { + &lhs - &rhs + } else { + &lhs + &modulus - &rhs + } + } + BlackBoxFunc::BigIntMul => lhs * rhs, + BlackBoxFunc::BigIntDiv => { + lhs * rhs.modpow(&(&modulus - BigUint::from(1_u32)), &modulus) + } //TODO ensure that modulus is prime + _ => unreachable!("ICE - bigint_op must be called for an operation"), + }; + if result > modulus { + let q = &result / &modulus; + result -= q * &modulus; + } + self.bigint_id_to_value.insert(output, result); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } +} diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 0f026cd274a..7146dff87e0 100644 --- a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -5,11 +5,12 @@ use acir::{ }; use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; -use self::pedersen::pedersen_hash; +use self::{bigint::BigIntSolver, pedersen::pedersen_hash}; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; +pub(crate) mod bigint; mod fixed_base_scalar_mul; mod hash; mod logic; @@ -53,6 +54,7 @@ pub(crate) fn solve( backend: &impl BlackBoxFunctionSolver, initial_witness: &mut WitnessMap, bb_func: &BlackBoxFuncCall, + bigint_solver: &mut BigIntSolver, ) -> Result<(), OpcodeResolutionError> { let inputs = bb_func.get_inputs_vec(); if !contains_all_inputs(initial_witness, &inputs) { @@ -190,12 +192,18 @@ pub(crate) fn solve( } // Recursive aggregation will be entirely handled by the backend and is not solved by the ACVM BlackBoxFuncCall::RecursiveAggregation { .. } => Ok(()), - BlackBoxFuncCall::BigIntAdd { .. } => todo!(), - BlackBoxFuncCall::BigIntNeg { .. } => todo!(), - BlackBoxFuncCall::BigIntMul { .. } => todo!(), - BlackBoxFuncCall::BigIntDiv { .. } => todo!(), - BlackBoxFuncCall::BigIntFromLeBytes { .. } => todo!(), - BlackBoxFuncCall::BigIntToLeBytes { .. } => todo!(), + BlackBoxFuncCall::BigIntAdd { lhs, rhs, output } + | BlackBoxFuncCall::BigIntSub { lhs, rhs, output } + | BlackBoxFuncCall::BigIntMul { lhs, rhs, output } + | BlackBoxFuncCall::BigIntDiv { lhs, rhs, output } => { + bigint_solver.bigint_op(*lhs, *rhs, *output, bb_func.get_black_box_func()) + } + BlackBoxFuncCall::BigIntFromLeBytes { inputs, modulus, output } => { + bigint_solver.bigint_from_bytes(inputs, modulus, *output, initial_witness) + } + BlackBoxFuncCall::BigIntToLeBytes { input, outputs } => { + bigint_solver.bigint_to_bytes(*input, outputs, initial_witness) + } BlackBoxFuncCall::Poseidon2Permutation { .. } => todo!(), BlackBoxFuncCall::Sha256Compression { .. } => todo!(), } diff --git a/noir/acvm-repo/acvm/src/pwg/brillig.rs b/noir/acvm-repo/acvm/src/pwg/brillig.rs index 4b62f86f0eb..c5a98aaf01c 100644 --- a/noir/acvm-repo/acvm/src/pwg/brillig.rs +++ b/noir/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,7 +1,10 @@ +use std::collections::HashMap; + use acir::{ brillig::{ForeignCallParam, ForeignCallResult, Value}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, + opcodes::BlockId, OpcodeLocation, }, native_types::WitnessMap, @@ -12,7 +15,7 @@ use brillig_vm::{VMStatus, VM}; use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; -use super::{get_value, insert_value}; +use super::{get_value, insert_value, memory_op::MemoryOpSolver}; #[derive(Debug)] pub enum BrilligSolverStatus { @@ -64,6 +67,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// witness. pub(super) fn new( initial_witness: &WitnessMap, + memory: &HashMap, brillig: &'b Brillig, bb_solver: &'b B, acir_index: usize, @@ -97,6 +101,18 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { } } } + BrilligInputs::MemoryArray(block_id) => { + let memory_block = memory + .get(block_id) + .ok_or(OpcodeNotSolvable::MissingMemoryBlock(block_id.0))?; + for memory_index in 0..memory_block.block_len { + let memory_value = memory_block + .block_value + .get(&memory_index) + .expect("All memory is initialized on creation"); + calldata.push((*memory_value).into()); + } + } } } diff --git a/noir/acvm-repo/acvm/src/pwg/memory_op.rs b/noir/acvm-repo/acvm/src/pwg/memory_op.rs index c1da2cd95cf..49ec652289e 100644 --- a/noir/acvm-repo/acvm/src/pwg/memory_op.rs +++ b/noir/acvm-repo/acvm/src/pwg/memory_op.rs @@ -14,8 +14,8 @@ type MemoryIndex = u32; /// Maintains the state for solving [`MemoryInit`][`acir::circuit::Opcode::MemoryInit`] and [`MemoryOp`][`acir::circuit::Opcode::MemoryOp`] opcodes. #[derive(Default)] pub(super) struct MemoryOpSolver { - block_value: HashMap, - block_len: u32, + pub(super) block_value: HashMap, + pub(super) block_len: u32, } impl MemoryOpSolver { diff --git a/noir/acvm-repo/acvm/src/pwg/mod.rs b/noir/acvm-repo/acvm/src/pwg/mod.rs index 41b96572658..2ee39a289e7 100644 --- a/noir/acvm-repo/acvm/src/pwg/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/mod.rs @@ -10,7 +10,10 @@ use acir::{ }; use acvm_blackbox_solver::BlackBoxResolutionError; -use self::{arithmetic::ExpressionSolver, directives::solve_directives, memory_op::MemoryOpSolver}; +use self::{ + arithmetic::ExpressionSolver, blackbox::bigint::BigIntSolver, directives::solve_directives, + memory_op::MemoryOpSolver, +}; use crate::BlackBoxFunctionSolver; use thiserror::Error; @@ -76,6 +79,8 @@ pub enum StepResult<'a, B: BlackBoxFunctionSolver> { pub enum OpcodeNotSolvable { #[error("missing assignment for witness index {0}")] MissingAssignment(u32), + #[error("Attempted to load uninitialized memory block")] + MissingMemoryBlock(u32), #[error("expression has too many unknowns {0}")] ExpressionHasTooManyUnknowns(Expression), } @@ -132,6 +137,8 @@ pub struct ACVM<'a, B: BlackBoxFunctionSolver> { /// Stores the solver for memory operations acting on blocks of memory disambiguated by [block][`BlockId`]. block_solvers: HashMap, + bigint_solver: BigIntSolver, + /// A list of opcodes which are to be executed by the ACVM. opcodes: &'a [Opcode], /// Index of the next opcode to be executed. @@ -149,6 +156,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { status, backend, block_solvers: HashMap::default(), + bigint_solver: BigIntSolver::default(), opcodes, instruction_pointer: 0, witness_map: initial_witness, @@ -254,9 +262,12 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let resolution = match opcode { Opcode::AssertZero(expr) => ExpressionSolver::solve(&mut self.witness_map, expr), - Opcode::BlackBoxFuncCall(bb_func) => { - blackbox::solve(self.backend, &mut self.witness_map, bb_func) - } + Opcode::BlackBoxFuncCall(bb_func) => blackbox::solve( + self.backend, + &mut self.witness_map, + bb_func, + &mut self.bigint_solver, + ), Opcode::Directive(directive) => solve_directives(&mut self.witness_map, directive), Opcode::MemoryInit { block_id, init } => { let solver = self.block_solvers.entry(*block_id).or_default(); @@ -327,7 +338,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { // there will be a cached `BrilligSolver` to avoid recomputation. let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { Some(solver) => solver, - None => BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?, + None => BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + )?, }; match solver.solve()? { BrilligSolverStatus::ForeignCallWait(foreign_call) => { @@ -362,7 +379,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { return StepResult::Status(self.handle_opcode_resolution(resolution)); } - let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + let solver = BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + ); match solver { Ok(solver) => StepResult::IntoBrillig(solver), Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), diff --git a/noir/acvm-repo/acvm/tests/solver.rs b/noir/acvm-repo/acvm/tests/solver.rs index 9ff4a4f4897..b267c3005a8 100644 --- a/noir/acvm-repo/acvm/tests/solver.rs +++ b/noir/acvm-repo/acvm/tests/solver.rs @@ -13,6 +13,7 @@ use acir::{ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; use acvm_blackbox_solver::StubbedBlackBoxSolver; +use brillig_vm::brillig::HeapValueType; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -69,7 +70,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, ], @@ -196,12 +199,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], @@ -327,12 +334,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], @@ -453,7 +464,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: Some(Expression::default()), diff --git a/noir/acvm-repo/acvm_js/test/shared/addition.ts b/noir/acvm-repo/acvm_js/test/shared/addition.ts index 982b9b685ce..217902bdea6 100644 --- a/noir/acvm-repo/acvm_js/test/shared/addition.ts +++ b/noir/acvm-repo/acvm_js/test/shared/addition.ts @@ -2,11 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `addition_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, 219, 96, 119, 89, 37, 40, - 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, - 111, 116, 133, 197, 69, 144, 153, 91, 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, - 86, 173, 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, 245, 233, 224, 1, 1, - 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, 182, 94, 165, 166, 122, + 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, + 138, 139, 197, 88, 68, 122, 205, 157, 152, 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, + 188, 162, 147, 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, 63, 243, 81, + 87, 163, 125, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ diff --git a/noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index faae98bcf47..27abd72305f 100644 --- a/noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,12 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 65, 10, 132, 48, 12, 76, 218, 237, 174, 123, 242, 11, 130, 62, 160, 250, - 2, 255, 34, 222, 20, 61, 250, 124, 11, 78, 49, 4, 193, 131, 21, 52, 16, 210, 132, 105, 50, 77, 210, 140, 136, 152, 54, - 177, 65, 13, 206, 12, 95, 74, 196, 181, 176, 254, 154, 212, 156, 46, 151, 191, 139, 163, 121, 1, 71, 123, 3, 199, 184, - 15, 15, 157, 119, 202, 185, 36, 237, 159, 61, 248, 63, 159, 160, 46, 232, 23, 254, 15, 54, 67, 156, 96, 11, 213, 119, - 82, 248, 116, 179, 104, 188, 163, 125, 15, 89, 213, 253, 139, 154, 221, 52, 206, 67, 191, 88, 5, 213, 52, 75, 113, - 174, 96, 205, 201, 157, 24, 207, 197, 211, 157, 6, 50, 18, 233, 158, 72, 89, 1, 53, 215, 75, 175, 196, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179, 154, 35, 8, 51, 7, 232, 204, + 9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213, 141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32, + 204, 48, 206, 18, 158, 19, 175, 37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156, + 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241, 250, 201, 99, 206, 251, + 96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47, 146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, + 20, 85, 75, 253, 136, 249, 87, 249, 105, 231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64, + 34, 14, 164, 69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts index 0437bebc369..c0859f50135 100644 --- a/noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,8 +1,8 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, 163, 175, 165, 10, 21, 36, - 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, - 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, 209, 247, 229, 130, 130, + 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, + 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/acvm-repo/acvm_js/test/shared/foreign_call.ts b/noir/acvm-repo/acvm_js/test/shared/foreign_call.ts index 7a65f29117c..0be8937b57d 100644 --- a/noir/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/noir/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 12, 68, 207, 148, 150, 118, 234, 175, 216, 63, 232, - 207, 116, 232, 210, 161, 136, 223, 175, 98, 132, 27, 212, 69, 31, 132, 28, 23, 8, 119, 59, 0, 131, 204, 66, 154, 41, - 222, 173, 219, 142, 113, 153, 121, 191, 44, 231, 21, 237, 144, 88, 43, 249, 11, 71, 156, 77, 245, 251, 249, 231, 119, - 189, 214, 204, 89, 187, 11, 25, 130, 54, 1, 36, 1, 124, 242, 107, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233, 212, 79, 177, 127, 208, 159, + 233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45, 119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190, + 50, 245, 26, 175, 218, 231, 165, 57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115, + 104, 181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/noir/acvm-repo/acvm_js/test/shared/memory_op.ts b/noir/acvm-repo/acvm_js/test/shared/memory_op.ts index ce88f491893..b5ab64b3447 100644 --- a/noir/acvm-repo/acvm_js/test/shared/memory_op.ts +++ b/noir/acvm-repo/acvm_js/test/shared/memory_op.ts @@ -1,9 +1,9 @@ // See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, 254, 255, 85, 198, 136, 9, - 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, - 148, 156, 203, 121, 89, 86, 13, 215, 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, - 235, 225, 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, 253, 167, 178, 144, 2, + 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, + 98, 174, 212, 177, 188, 187, 92, 255, 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, + 19, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/acvm-repo/acvm_js/test/shared/pedersen.ts b/noir/acvm-repo/acvm_js/test/shared/pedersen.ts index e35893fc355..5150d24131c 100644 --- a/noir/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/noir/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,7 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, 138, 10, 34, 65, 84, 198, - 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, 27, 196, 64, 200, 100, 0, 15, + 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, 48, 224, 71, 90, 33, 97, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index 5716cbd30f8..2127de66f69 100644 --- a/noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -1,17 +1,17 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, - 193, 19, 142, 243, 183, 255, 14, 179, 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, - 25, 206, 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, 205, 29, 238, 114, - 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, - 139, 188, 97, 137, 183, 44, 243, 142, 21, 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, - 223, 142, 241, 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, 47, 186, 139, - 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, 138, 126, 162, 157, 232, 38, 154, 137, 94, - 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, - 176, 121, 236, 29, 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, 42, 219, - 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, 219, 109, 59, 110, 218, 117, 203, - 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, 239, 189, 119, 141, 93, 99, + 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, + 234, 219, 204, 146, 239, 91, 170, 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, + 236, 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, 115, 156, 231, 2, 23, + 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, + 158, 240, 148, 103, 60, 231, 5, 47, 121, 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, + 158, 125, 126, 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, 189, 165, 181, + 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, 210, 78, 186, 73, 51, 233, 37, 173, 164, + 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, + 235, 236, 156, 141, 179, 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, 187, 126, 184, 103, 217, + 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, 239, 128, 225, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/acvm-repo/brillig/src/black_box.rs b/noir/acvm-repo/brillig/src/black_box.rs index 9195d8aa6f3..29861d0fd84 100644 --- a/noir/acvm-repo/brillig/src/black_box.rs +++ b/noir/acvm-repo/brillig/src/black_box.rs @@ -85,7 +85,7 @@ pub enum BlackBoxOp { rhs: MemoryAddress, output: MemoryAddress, }, - BigIntNeg { + BigIntSub { lhs: MemoryAddress, rhs: MemoryAddress, output: MemoryAddress, diff --git a/noir/acvm-repo/brillig/src/lib.rs b/noir/acvm-repo/brillig/src/lib.rs index 2e9d80e2f3b..0661e794360 100644 --- a/noir/acvm-repo/brillig/src/lib.rs +++ b/noir/acvm-repo/brillig/src/lib.rs @@ -17,7 +17,9 @@ mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; -pub use opcodes::{BinaryFieldOp, BinaryIntOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}; +pub use opcodes::{ + BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +}; pub use opcodes::{BrilligOpcode as Opcode, Label}; pub use value::Typ; pub use value::Value; diff --git a/noir/acvm-repo/brillig/src/opcodes.rs b/noir/acvm-repo/brillig/src/opcodes.rs index 9a6f11c463f..51df1f90941 100644 --- a/noir/acvm-repo/brillig/src/opcodes.rs +++ b/noir/acvm-repo/brillig/src/opcodes.rs @@ -19,6 +19,27 @@ impl From for MemoryAddress { } } +/// Describes the memory layout for an array/vector element +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum HeapValueType { + // A single field element is enough to represent the value + Simple, + // The value read should be interpreted as a pointer to a heap array, which + // consists of a pointer to a slice of memory of size elements, and a + // reference count + Array { value_types: Vec, size: usize }, + // The value read should be interpreted as a pointer to a heap vector, which + // consists of a pointer to a slice of memory, a number of elements in that + // slice, and a reference count + Vector { value_types: Vec }, +} + +impl HeapValueType { + pub fn all_simple(types: &[HeapValueType]) -> bool { + types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + } +} + /// A fixed-sized array starting from a Brillig memory location. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapArray { @@ -77,6 +98,11 @@ pub enum BrilligOpcode { lhs: MemoryAddress, rhs: MemoryAddress, }, + Cast { + destination: MemoryAddress, + source: MemoryAddress, + bit_size: u32, + }, JumpIfNot { condition: MemoryAddress, location: Label, @@ -104,6 +130,7 @@ pub enum BrilligOpcode { }, Const { destination: MemoryAddress, + bit_size: u32, value: Value, }, Return, @@ -117,8 +144,13 @@ pub enum BrilligOpcode { function: String, /// Destination addresses (may be single values or memory pointers). destinations: Vec, + /// Destination value types + destination_value_types: Vec, /// Input addresses (may be single values or memory pointers). inputs: Vec, + /// Input value types (for heap allocated structures indicates how to + /// retrieve the elements) + input_value_types: Vec, }, Mov { destination: MemoryAddress, diff --git a/noir/acvm-repo/brillig_vm/src/black_box.rs b/noir/acvm-repo/brillig_vm/src/black_box.rs index de20d194dde..04aa2bcf9af 100644 --- a/noir/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/acvm-repo/brillig_vm/src/black_box.rs @@ -179,7 +179,7 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::BigIntAdd { .. } => todo!(), - BlackBoxOp::BigIntNeg { .. } => todo!(), + BlackBoxOp::BigIntSub { .. } => todo!(), BlackBoxOp::BigIntMul { .. } => todo!(), BlackBoxOp::BigIntDiv { .. } => todo!(), BlackBoxOp::BigIntFromLeBytes { .. } => todo!(), @@ -204,7 +204,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, BlackBoxOp::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, BlackBoxOp::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxOp::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxOp::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxOp::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxOp::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxOp::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, diff --git a/noir/acvm-repo/brillig_vm/src/lib.rs b/noir/acvm-repo/brillig_vm/src/lib.rs index 0c90fcb1416..081ecd33cb6 100644 --- a/noir/acvm-repo/brillig_vm/src/lib.rs +++ b/noir/acvm-repo/brillig_vm/src/lib.rs @@ -12,8 +12,8 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, - MemoryAddress, Opcode, Value, ValueOrArray, + BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, + HeapVector, MemoryAddress, Opcode, Value, ValueOrArray, }; use acir::FieldElement; // Re-export `brillig`. @@ -183,6 +183,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.increment_program_counter() } } + Opcode::Cast { destination: destination_address, source: source_address, bit_size } => { + let source_value = self.memory.read(*source_address); + let casted_value = self.cast(*bit_size, source_value); + self.memory.write(*destination_address, casted_value); + self.increment_program_counter() + } Opcode::Jump { location: destination } => self.set_program_counter(*destination), Opcode::JumpIf { condition, location: destination } => { // Check if condition is true @@ -212,7 +218,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.fail("return opcode hit, but callstack already empty".to_string()) } } - Opcode::ForeignCall { function, destinations, inputs } => { + Opcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert!(inputs.len() == input_value_types.len()); + assert!(destinations.len() == destination_value_types.len()); + if self.foreign_call_counter >= self.foreign_call_results.len() { // When this opcode is called, it is possible that the results of a foreign call are // not yet known (not enough entries in `foreign_call_results`). @@ -223,7 +238,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_memory_values(*input)) + .zip(input_value_types) + .map(|(input, input_type)| self.get_memory_values(*input, input_type)) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -231,48 +247,69 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let values = &self.foreign_call_results[self.foreign_call_counter].values; let mut invalid_foreign_call_result = false; - for (destination, output) in destinations.iter().zip(values) { - match destination { - ValueOrArray::MemoryAddress(value_index) => match output { - ForeignCallParam::Single(value) => { - self.memory.write(*value_index, *value); - } - _ => unreachable!( - "Function result size does not match brillig bytecode (expected 1 result)" - ), - }, - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }) => { + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { + match (destination, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; - } - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + ForeignCallParam::Single(value) => { + self.memory.write(*value_index, *value); } + _ => unreachable!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" + ), } } - ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size address - self.memory.write(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if size == type_size => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + invalid_foreign_call_result = true; + break; + } + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + } else { + unimplemented!("deflattening heap arrays from foreign calls"); + } + } + ( + ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size address + self.memory.write(*size_index, Value::from(values.len())); + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); } } + _ => { + unreachable!("Unexpected value type {value_type:?} for destination {destination:?}"); + } } } @@ -316,7 +353,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.call_stack.push(Value::from(self.program_counter)); self.set_program_counter(*location) } - Opcode::Const { destination, value } => { + Opcode::Const { destination, value, bit_size: _ } => { self.memory.write(*destination, *value); self.increment_program_counter() } @@ -351,21 +388,85 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - fn get_memory_values(&self, input: ValueOrArray) -> ForeignCallParam { - match input { - ValueOrArray::MemoryAddress(value_index) => self.memory.read(value_index).into(), - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }) => { + fn get_memory_values( + &self, + input: ValueOrArray, + value_type: &HeapValueType, + ) -> ForeignCallParam { + match (input, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { + self.memory.read(value_index).into() + } + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if *type_size == size => { let start = self.memory.read_ref(pointer_index); - self.memory.read_slice(start, size).to_vec().into() + self.read_slice_of_values_from_memory(start, size, value_types).into() } - ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { + ( + ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { let start = self.memory.read_ref(pointer_index); - let size = self.memory.read(size_index); - self.memory.read_slice(start, size.to_usize()).to_vec().into() + let size = self.memory.read(size_index).to_usize(); + self.read_slice_of_values_from_memory(start, size, value_types).into() + } + _ => { + unreachable!("Unexpected value type {value_type:?} for input {input:?}"); } } } + /// Reads an array/vector from memory but recursively reads pointers to + /// nested arrays/vectors according to the sequence of value types. + fn read_slice_of_values_from_memory( + &self, + start: MemoryAddress, + size: usize, + value_types: &[HeapValueType], + ) -> Vec { + if HeapValueType::all_simple(value_types) { + self.memory.read_slice(start, size).to_vec() + } else { + // Check that the sequence of value types fit an integer number of + // times inside the given size. + assert!( + 0 == size % value_types.len(), + "array/vector does not contain a whole number of elements" + ); + (0..size) + .zip(value_types.iter().cycle()) + .flat_map(|(i, value_type)| { + let value_address: MemoryAddress = (start.to_usize() + i).into(); + match value_type { + HeapValueType::Simple => { + let value = self.memory.read(value_address); + vec![value] + } + HeapValueType::Array { value_types, size } => { + let array_address = self.memory.read_ref(value_address); + let array_start = self.memory.read_ref(array_address); + self.read_slice_of_values_from_memory(array_start, *size, value_types) + } + HeapValueType::Vector { value_types } => { + let vector_address = self.memory.read_ref(value_address); + let vector_start = self.memory.read_ref(vector_address); + let size_address: MemoryAddress = + (vector_address.to_usize() + 1).into(); + let vector_size = self.memory.read(size_address).to_usize(); + self.read_slice_of_values_from_memory( + vector_start, + vector_size, + value_types, + ) + } + } + }) + .collect::>() + } + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( @@ -406,6 +507,13 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { .write(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into()); Ok(()) } + + /// Casts a value to a different bit size. + fn cast(&self, bit_size: u32, value: Value) -> Value { + let lhs_big = BigUint::from_bytes_be(&value.to_field().to_be_bytes()); + let mask = BigUint::from(2_u32).pow(bit_size) - 1_u32; + FieldElement::from_be_bytes_reduce(&(lhs_big & mask).to_bytes_be()).into() + } } pub(crate) struct DummyBlackBoxSolver; @@ -603,6 +711,40 @@ mod tests { assert_eq!(output_value, Value::from(false)); } + #[test] + fn cast_opcode() { + let calldata = vec![Value::from((2_u128.pow(32)) - 1)]; + + let opcodes = &[ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 1, + offset: 0, + }, + Opcode::Cast { + destination: MemoryAddress::from(1), + source: MemoryAddress::from(0), + bit_size: 8, + }, + Opcode::Stop { return_data_offset: 1, return_data_size: 1 }, + ]; + let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::Finished { return_data_offset: 1, return_data_size: 1 }); + + let VM { memory, .. } = vm; + + let casted_value = memory.read(MemoryAddress::from(1)); + assert_eq!(casted_value, Value::from(2_u128.pow(8) - 1)); + } + #[test] fn mov_opcode() { let calldata = vec![Value::from(1u128), Value::from(2u128), Value::from(3u128)]; @@ -737,17 +879,21 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = memory.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(item_count as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(item_count as u128), + bit_size: 32, + }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into() }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, ]; let loop_body = [ // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -816,13 +962,17 @@ mod tests { let start = [ // sum = 0 - Opcode::Const { destination: r_sum, value: 0u128.into() }, + Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: 32 }, // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = array.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(memory.len() as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(memory.len() as u128), + bit_size: 32, + }, // pointer = array_ptr - Opcode::Const { destination: r_pointer, value: 5u128.into() }, + Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size: 32 }, Opcode::CalldataCopy { destination_address: MemoryAddress(5), size: memory.len(), @@ -841,7 +991,7 @@ mod tests { bit_size, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -908,11 +1058,11 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = size - Opcode::Const { destination: r_len, value: size.into() }, + Opcode::Const { destination: r_len, value: size.into(), bit_size: 32 }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into() }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, // call recursive_fn Opcode::Call { location: 5, // Call after 'start' @@ -938,7 +1088,7 @@ mod tests { // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1008,12 +1158,14 @@ mod tests { let double_program = vec![ // Load input address with value 5 - Opcode::Const { destination: r_input, value: Value::from(5u128) }, + Opcode::Const { destination: r_input, value: Value::from(5u128), bit_size: 32 }, // Call foreign function "double" with the input address Opcode::ForeignCall { function: "double".into(), destinations: vec![ValueOrArray::MemoryAddress(r_result)], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(r_input)], + input_value_types: vec![HeapValueType::Simple], }, ]; @@ -1067,9 +1219,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: 2_usize.into() }, + Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: 2_usize.into() }, + Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1077,10 +1229,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + value_types: vec![HeapValueType::Simple], + size: initial_matrix.len(), + }], }, ]; @@ -1138,18 +1298,24 @@ mod tests { offset: 0, }, // input_pointer = 4 - Opcode::Const { destination: r_input_pointer, value: Value::from(4u128) }, + Opcode::Const { destination: r_input_pointer, value: Value::from(4u128), bit_size: 32 }, // input_size = input_string.len() (constant here) - Opcode::Const { destination: r_input_size, value: Value::from(input_string.len()) }, + Opcode::Const { + destination: r_input_size, + value: Value::from(input_string.len()), + bit_size: 32, + }, // output_pointer = 4 + input_size Opcode::Const { destination: r_output_pointer, value: Value::from(4 + input_string.len()), + bit_size: 32, }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, value: Value::from(input_string.len() * 2), + bit_size: 32, }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { @@ -1158,10 +1324,16 @@ mod tests { pointer: r_output_pointer, size: r_output_size, })], + destination_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], + input_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1218,9 +1390,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(2u128) }, + Opcode::Const { destination: r_input, value: Value::from(2u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(6u128) }, + Opcode::Const { destination: r_output, value: Value::from(6u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1228,10 +1400,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1299,11 +1479,11 @@ mod tests { offset: 0, }, // input = 3 - Opcode::Const { destination: r_input_a, value: Value::from(3u128) }, + Opcode::Const { destination: r_input_a, value: Value::from(3u128), bit_size: 32 }, // input = 7 - Opcode::Const { destination: r_input_b, value: Value::from(7u128) }, + Opcode::Const { destination: r_input_b, value: Value::from(7u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128) }, + Opcode::Const { destination: r_output, value: Value::from(0u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1311,10 +1491,24 @@ mod tests { pointer: r_output, size: matrix_a.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ ValueOrArray::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len() }), ValueOrArray::HeapArray(HeapArray { pointer: r_input_b, size: matrix_b.len() }), ], + input_value_types: vec![ + HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }, + HeapValueType::Array { + size: matrix_b.len(), + value_types: vec![HeapValueType::Simple], + }, + ], }, ]; let mut initial_memory = matrix_a.clone(); @@ -1346,4 +1540,121 @@ mod tests { // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn foreign_call_opcode_nested_arrays_and_slices_input() { + // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] + + let v2 = vec![Value::from(2u128), Value::from(3u128)]; + let a4 = vec![Value::from(4u128)]; + let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; + let a9 = vec![Value::from(9u128)]; + + // construct memory by declaring all inner arrays/vectors first + let v2_ptr = 0u128; + let mut memory = v2.clone(); + let v2_start = memory.len(); + memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + let a4_ptr = memory.len(); + memory.extend(a4.clone()); + let a4_start = memory.len(); + memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + let v6_ptr = memory.len(); + memory.extend(v6.clone()); + let v6_start = memory.len(); + memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + let a9_ptr = memory.len(); + memory.extend(a9.clone()); + let a9_start = memory.len(); + memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + // finally we add the contents of the outer array + let outer_ptr = memory.len(); + let outer_array = vec![ + Value::from(1u128), + Value::from(v2.len()), + Value::from(v2_start), + Value::from(a4_start), + Value::from(5u128), + Value::from(v6.len()), + Value::from(v6_start), + Value::from(a9_start), + ]; + memory.extend(outer_array.clone()); + + let input_array_value_types = vec![ + HeapValueType::Simple, + HeapValueType::Simple, // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, + HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + ]; + + // memory address of the end of the above data structures + let r_ptr = memory.len(); + + let r_input = MemoryAddress::from(r_ptr); + let r_output = MemoryAddress::from(r_ptr + 1); + + let program = vec![ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: memory.len(), + offset: 0, + }, + // input = 0 + Opcode::Const { destination: r_input, value: Value::from(outer_ptr), bit_size: 32 }, + // some_function(input) + Opcode::ForeignCall { + function: "flat_sum".into(), + destinations: vec![ValueOrArray::MemoryAddress(r_output)], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + })], + input_value_types: vec![HeapValueType::Array { + value_types: input_array_value_types, + size: outer_array.len(), + }], + }, + ]; + + let mut vm = brillig_execute_and_get_vm(memory, &program); + + // Check that VM is waiting + assert_eq!( + vm.status, + VMStatus::ForeignCallWait { + function: "flat_sum".into(), + inputs: vec![ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ])], + } + ); + + // Push result we're waiting for + vm.resolve_foreign_call(Value::from(45u128).into()); + + // Resume VM + brillig_execute(&mut vm); + + // Check that VM finished once resumed + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + // Check result + let result_value = vm.memory.read(r_output); + assert_eq!(result_value, Value::from(45u128)); + + // Ensure the foreign call counter has been incremented + assert_eq!(vm.foreign_call_counter, 1); + } } diff --git a/noir/aztec_macros/Cargo.toml b/noir/aztec_macros/Cargo.toml index 04f74d3b022..5e908b2e672 100644 --- a/noir/aztec_macros/Cargo.toml +++ b/noir/aztec_macros/Cargo.toml @@ -12,3 +12,4 @@ repository.workspace = true [dependencies] noirc_frontend.workspace = true iter-extended.workspace = true +convert_case = "0.6.0" diff --git a/noir/aztec_macros/src/lib.rs b/noir/aztec_macros/src/lib.rs index 228664c83fb..2143fbf6e3d 100644 --- a/noir/aztec_macros/src/lib.rs +++ b/noir/aztec_macros/src/lib.rs @@ -1,6 +1,7 @@ use std::borrow::{Borrow, BorrowMut}; use std::vec; +use convert_case::{Case, Casing}; use iter_extended::vecmap; use noirc_frontend::macros_api::FieldElement; use noirc_frontend::macros_api::{ @@ -645,6 +646,10 @@ fn transform_vm_function( func: &mut NoirFunction, _storage_defined: bool, ) -> Result<(), AztecMacroError> { + // Push Avm context creation to the beginning of the function + let create_context = create_avm_context()?; + func.def.body.0.insert(0, create_context); + // We want the function to be seen as a public function func.def.is_open = true; @@ -1045,7 +1050,10 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { fn create_inputs(ty: &str) -> Param { let context_ident = ident("inputs"); let context_pattern = Pattern::Identifier(context_ident); - let type_path = chained_path!("aztec", "abi", ty); + + let path_snippet = ty.to_case(Case::Snake); // e.g. private_context_inputs + let type_path = chained_path!("aztec", "context", "inputs", &path_snippet, ty); + let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![])); let visibility = Visibility::Private; @@ -1084,8 +1092,8 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac let let_hasher = mutable_assignment( "hasher", // Assigned to call( - variable_path(chained_path!("aztec", "abi", "Hasher", "new")), // Path - vec![], // args + variable_path(chained_path!("aztec", "hasher", "Hasher", "new")), // Path + vec![], // args ), ); @@ -1144,12 +1152,14 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac vec![], // args ); + let path_snippet = ty.to_case(Case::Snake); // e.g. private_context + // let mut context = {ty}::new(inputs, hash); let let_context = mutable_assignment( "context", // Assigned to call( - variable_path(chained_path!("aztec", "context", ty, "new")), // Path - vec![inputs_expression, hash_call], // args + variable_path(chained_path!("aztec", "context", &path_snippet, ty, "new")), // Path + vec![inputs_expression, hash_call], // args ), ); injected_expressions.push(let_context); @@ -1158,6 +1168,35 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac Ok(injected_expressions) } +/// Creates an mutable avm context +/// +/// ```noir +/// /// Before +/// #[aztec(public-vm)] +/// fn foo() -> Field { +/// let mut context = aztec::context::AVMContext::new(); +/// let timestamp = context.timestamp(); +/// // ... +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() -> Field { +/// let mut timestamp = context.timestamp(); +/// // ... +/// } +fn create_avm_context() -> Result { + let let_context = mutable_assignment( + "context", // Assigned to + call( + variable_path(chained_path!("aztec", "context", "AVMContext", "new")), // Path + vec![], // args + ), + ); + + Ok(let_context) +} + /// Abstract Return Type /// /// This function intercepts the function's current return type and replaces it with pushes @@ -1167,7 +1206,7 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac /// ```noir /// /// Before /// #[aztec(private)] -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// let my_return_value: Field = 10; /// context.return_values.push(my_return_value); @@ -1343,8 +1382,8 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// Create Return Type /// -/// Public functions return abi::PublicCircuitPublicInputs while -/// private functions return abi::PrivateCircuitPublicInputs +/// Public functions return protocol_types::abis::public_circuit_public_inputs::PublicCircuitPublicInputs while +/// private functions return protocol_types::abis::private_circuit_public_inputs::::PrivateCircuitPublicInputs /// /// This call constructs an ast token referencing the above types /// The name is set in the function above `transform`, hence the @@ -1354,7 +1393,7 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// ```noir /// /// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// } /// @@ -1364,7 +1403,8 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// // ... /// } fn create_return_type(ty: &str) -> FunctionReturnType { - let return_path = chained_path!("aztec", "abi", ty); + let path_snippet = ty.to_case(Case::Snake); // e.g. private_circuit_public_inputs or public_circuit_public_inputs + let return_path = chained_path!("aztec", "protocol_types", "abis", &path_snippet, ty); return_type(return_path) } @@ -1376,7 +1416,7 @@ fn create_return_type(ty: &str) -> FunctionReturnType { /// The replaced code: /// ```noir /// /// Before -/// fn foo() -> abi::PrivateCircuitPublicInputs { +/// fn foo() -> protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs { /// // ... /// context.finish() /// } diff --git a/noir/compiler/noirc_driver/src/lib.rs b/noir/compiler/noirc_driver/src/lib.rs index 6fd69f8b576..cded514f28c 100644 --- a/noir/compiler/noirc_driver/src/lib.rs +++ b/noir/compiler/noirc_driver/src/lib.rs @@ -3,7 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -87,12 +87,14 @@ pub struct CompileOptions { fn parse_expression_width(input: &str) -> Result { use std::io::{Error, ErrorKind}; - let width = input .parse::() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } /// Helper type used to signify where only warnings are expected in file diagnostics diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 96d80cb8131..dfe23b45034 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -244,13 +244,13 @@ pub(crate) fn convert_black_box_call( ) } } - BlackBoxFunc::BigIntNeg => { + BlackBoxFunc::BigIntSub => { if let ( [BrilligVariable::Simple(lhs), BrilligVariable::Simple(rhs)], [BrilligVariable::Simple(output)], ) = (function_arguments, function_results) { - brillig_context.black_box_op_instruction(BlackBoxOp::BigIntNeg { + brillig_context.black_box_op_instruction(BlackBoxOp::BigIntSub { lhs: *lhs, rhs: *rhs, output: *output, diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index ae8adeb10ec..e0630655253 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,4 +1,6 @@ -use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, +}; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; @@ -22,7 +24,7 @@ use num_bigint::BigUint; use super::brillig_black_box::convert_black_box_call; use super::brillig_block_variables::BlockVariables; -use super::brillig_fn::FunctionContext; +use super::brillig_fn::{get_bit_size_from_ssa_type, FunctionContext}; /// Generate the compilation artifacts for compiling a function into brillig bytecode. pub(crate) struct BrilligBlock<'block> { @@ -85,16 +87,6 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_terminator(terminator_instruction, dfg); } - fn get_bit_size_from_ssa_type(typ: Type) -> u32 { - match typ { - Type::Numeric(num_type) => match num_type { - NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => bit_size, - NumericType::NativeField => FieldElement::max_num_bits(), - }, - _ => unreachable!("ICE bitwise not on a non numeric type"), - } - } - /// Creates a unique global label for a block. /// /// This uses the current functions's function ID and the block ID @@ -322,7 +314,7 @@ impl<'block> BrilligBlock<'block> { dfg.instruction_results(instruction_id)[0], dfg, ); - let bit_size = Self::get_bit_size_from_ssa_type(dfg.type_of_value(*value)); + let bit_size = get_bit_size_from_ssa_type(&dfg.type_of_value(*value)); self.brillig_context.not_instruction(condition_register, bit_size, result_register); } Instruction::Call { func, arguments } => match &dfg[*func] { @@ -332,13 +324,23 @@ impl<'block> BrilligBlock<'block> { let input_registers = vecmap(arguments, |value_id| { self.convert_ssa_value(*value_id, dfg).to_register_or_memory() }); + let input_value_types = vecmap(arguments, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); let output_registers = vecmap(result_ids, |value_id| { self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() }); + let output_value_types = vecmap(result_ids, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), &input_registers, + &input_value_types, &output_registers, + &output_value_types, ); for (i, output_register) in output_registers.iter().enumerate() { @@ -499,7 +501,9 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::Simple(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self.brillig_context.make_constant(2_usize.into()); + let radix = self + .brillig_context + .make_constant(2_usize.into(), FieldElement::max_num_bits()); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len, limb_count); @@ -533,7 +537,7 @@ impl<'block> BrilligBlock<'block> { *bit_size, ); } - Instruction::Cast(value, _) => { + Instruction::Cast(value, typ) => { let result_ids = dfg.instruction_results(instruction_id); let destination_register = self.variables.define_register_variable( self.function_context, @@ -542,7 +546,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); let source_register = self.convert_ssa_register_value(*value, dfg); - self.convert_cast(destination_register, source_register); + self.convert_cast(destination_register, source_register, typ); } Instruction::ArrayGet { array, index } => { let result_ids = dfg.instruction_results(instruction_id); @@ -596,6 +600,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.const_instruction( right, FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::max_num_bits(), ); let brillig_binary_op = BrilligBinaryOp::Integer { @@ -696,7 +701,7 @@ impl<'block> BrilligBlock<'block> { ) { let (size_as_register, should_deallocate_size) = match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - (self.brillig_context.make_constant(size.into()), true) + (self.brillig_context.make_usize_constant(size.into()), true) } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => (size, false), _ => unreachable!("ICE: validate array index on non-array"), @@ -763,7 +768,7 @@ impl<'block> BrilligBlock<'block> { let (source_pointer, source_size_as_register) = match source_variable { BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.const_instruction(source_size_register, size.into()); + self.brillig_context.usize_const(source_size_register, size.into()); (pointer, source_size_register) } BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { @@ -774,7 +779,7 @@ impl<'block> BrilligBlock<'block> { _ => unreachable!("ICE: array set on non-array"), }; - let one = self.brillig_context.make_constant(1_usize.into()); + let one = self.brillig_context.make_usize_constant(1_usize.into()); let condition = self.brillig_context.allocate_register(); self.brillig_context.binary_instruction( @@ -802,7 +807,7 @@ impl<'block> BrilligBlock<'block> { match destination_variable { BrilligVariable::BrilligArray(BrilligArray { rc: target_rc, .. }) => { - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } BrilligVariable::BrilligVector(BrilligVector { size: target_size, @@ -810,7 +815,7 @@ impl<'block> BrilligBlock<'block> { .. }) => { self.brillig_context.mov_instruction(target_size, source_size_as_register); - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } _ => unreachable!("ICE: array set on non-array"), } @@ -1022,7 +1027,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, @@ -1065,7 +1070,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, user_index, @@ -1121,11 +1126,11 @@ impl<'block> BrilligBlock<'block> { /// Converts an SSA cast to a sequence of Brillig opcodes. /// Casting is only necessary when shrinking the bit size of a numeric value. - fn convert_cast(&mut self, destination: MemoryAddress, source: MemoryAddress) { + fn convert_cast(&mut self, destination: MemoryAddress, source: MemoryAddress, typ: &Type) { // We assume that `source` is a valid `target_type` as it's expected that a truncate instruction was emitted // to ensure this is the case. - self.brillig_context.mov_instruction(destination, source); + self.brillig_context.cast_instruction(destination, source, get_bit_size_from_ssa_type(typ)); } /// Converts the Binary instruction into a sequence of Brillig opcodes. @@ -1158,7 +1163,7 @@ impl<'block> BrilligBlock<'block> { // converted to registers so we fetch from the cache. self.variables.get_allocation(self.function_context, value_id, dfg) } - Value::NumericConstant { constant, .. } => { + Value::NumericConstant { constant, typ } => { // Constants might have been converted previously or not, so we get or create and // (re)initialize the value inside. if let Some(variable) = self.variables.get_constant(value_id, dfg) { @@ -1168,7 +1173,11 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); let register_index = new_variable.extract_register(); - self.brillig_context.const_instruction(register_index, (*constant).into()); + self.brillig_context.const_instruction( + register_index, + (*constant).into(), + get_bit_size_from_ssa_type(typ), + ); new_variable } } @@ -1184,16 +1193,15 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::BrilligArray(brillig_array) => { self.brillig_context .allocate_fixed_length_array(brillig_array.pointer, array.len()); - self.brillig_context - .const_instruction(brillig_array.rc, 1_usize.into()); + self.brillig_context.usize_const(brillig_array.rc, 1_usize.into()); brillig_array.pointer } BrilligVariable::BrilligVector(vector) => { - self.brillig_context.const_instruction(vector.size, array.len().into()); + self.brillig_context.usize_const(vector.size, array.len().into()); self.brillig_context .allocate_array_instruction(vector.pointer, vector.size); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); vector.pointer } @@ -1205,7 +1213,8 @@ impl<'block> BrilligBlock<'block> { // Write the items // Allocate a register for the iterator - let iterator_register = self.brillig_context.make_constant(0_usize.into()); + let iterator_register = + self.brillig_context.make_usize_constant(0_usize.into()); for element_id in array.iter() { let element_variable = self.convert_ssa_value(*element_id, dfg); @@ -1263,7 +1272,7 @@ impl<'block> BrilligBlock<'block> { ); let array = variable.extract_array(); self.brillig_context.allocate_fixed_length_array(array.pointer, array.size); - self.brillig_context.const_instruction(array.rc, 1_usize.into()); + self.brillig_context.usize_const(array.rc, 1_usize.into()); variable } @@ -1280,7 +1289,7 @@ impl<'block> BrilligBlock<'block> { // The stack pointer will then be updated by the caller of this method // once the external call is resolved and the array size is known self.brillig_context.set_array_pointer(vector.pointer); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); variable } @@ -1304,8 +1313,7 @@ impl<'block> BrilligBlock<'block> { match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - self.brillig_context - .const_instruction(result_register, (size / element_size).into()); + self.brillig_context.usize_const(result_register, (size / element_size).into()); } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { self.brillig_context.usize_op( diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 5ac2ecf06be..93c4b1a5042 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,5 +1,6 @@ -use acvm::acir::brillig::{ - BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value, +use acvm::{ + acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value}, + FieldElement, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; @@ -24,7 +25,11 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // If the input is zero, then we jump to the stop opcode BrilligOpcode::JumpIfNot { condition: input, location: stop_location }, // Put value one in register (1) - BrilligOpcode::Const { destination: one_const, value: Value::from(1_usize) }, + BrilligOpcode::Const { + destination: one_const, + value: Value::from(1_usize), + bit_size: FieldElement::max_num_bits(), + }, // Divide 1 by the input, and set the result of the division into register (0) BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Div, diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs index 026def4ef11..e96a756a9ee 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs @@ -1,16 +1,17 @@ +use acvm::FieldElement; use iter_extended::vecmap; use crate::{ brillig::brillig_ir::{ artifact::{BrilligParameter, Label}, brillig_variable::BrilligVariable, - BrilligContext, + BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }, ssa::ir::{ basic_block::BasicBlockId, function::{Function, FunctionId}, post_order::PostOrder, - types::Type, + types::{NumericType, Type}, value::ValueId, }, }; @@ -72,7 +73,9 @@ impl FunctionContext { fn ssa_type_to_parameter(typ: &Type) -> BrilligParameter { match typ { - Type::Numeric(_) | Type::Reference(_) => BrilligParameter::Simple, + Type::Numeric(_) | Type::Reference(_) => { + BrilligParameter::Simple(get_bit_size_from_ssa_type(typ)) + } Type::Array(item_type, size) => BrilligParameter::Array( vecmap(item_type.iter(), |item_typ| { FunctionContext::ssa_type_to_parameter(item_typ) @@ -110,3 +113,14 @@ impl FunctionContext { .collect() } } + +pub(crate) fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { + match typ { + Type::Numeric(num_type) => match num_type { + NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => *bit_size, + NumericType::NativeField => FieldElement::max_num_bits(), + }, + Type::Reference(_) => BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + _ => unreachable!("ICE bitwise not on a non numeric type"), + } +} diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 981a16a01b2..933396be0cb 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -20,7 +20,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy the source vector into the target vector self.brillig_context.copy_array_instruction( @@ -30,7 +30,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, source_vector.size, @@ -57,7 +57,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the target pointer by variables_to_insert.len() let destination_copy_pointer = self.brillig_context.allocate_register(); @@ -77,7 +77,7 @@ impl<'block> BrilligBlock<'block> { // Then we write the items to insert at the start for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -100,7 +100,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the source pointer by removed_items.len() let source_copy_pointer = self.brillig_context.allocate_register(); @@ -119,7 +119,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -142,7 +142,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy all elements except the last items into the target vector self.brillig_context.copy_array_instruction( @@ -152,7 +152,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, target_vector.size, @@ -180,7 +180,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -225,7 +225,7 @@ impl<'block> BrilligBlock<'block> { // Write the items to insert starting at the index for (subitem_index, variable) in items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); @@ -252,7 +252,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -298,7 +298,7 @@ impl<'block> BrilligBlock<'block> { // Get the removed items for (subitem_index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); @@ -339,7 +339,7 @@ mod tests { use crate::brillig::brillig_ir::tests::{ create_and_run_vm, create_context, create_entry_point_bytecode, }; - use crate::brillig::brillig_ir::BrilligContext; + use crate::brillig::brillig_ir::{BrilligContext, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE}; use crate::ssa::function_builder::FunctionBuilder; use crate::ssa::ir::function::RuntimeType; use crate::ssa::ir::map::Id; @@ -378,11 +378,16 @@ mod tests { expected_return: Vec, ) { let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, + BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len(), + ), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ]; - let returns = - vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1)]; + let returns = vec![BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len() + 1, + )]; let (_, mut function_context, mut context) = create_test_environment(); @@ -466,11 +471,16 @@ mod tests { expected_return_array: Vec, expected_return_item: Value, ) { - let arguments = - vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len())]; + let arguments = vec![BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len(), + )]; let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), - BrilligParameter::Simple, + BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len() - 1, + ), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ]; let (_, mut function_context, mut context) = create_test_environment(); @@ -548,12 +558,17 @@ mod tests { expected_return: Vec, ) { let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, - BrilligParameter::Simple, + BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len(), + ), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ]; - let returns = - vec![BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() + 1)]; + let returns = vec![BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len() + 1, + )]; let (_, mut function_context, mut context) = create_test_environment(); @@ -660,12 +675,18 @@ mod tests { expected_removed_item: Value, ) { let arguments = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len()), - BrilligParameter::Simple, + BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len(), + ), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ]; let returns = vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], array.len() - 1), - BrilligParameter::Simple, + BrilligParameter::Array( + vec![BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE)], + array.len() - 1, + ), + BrilligParameter::Simple(BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ]; let (_, mut function_context, mut context) = create_test_environment(); diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index b094ff9c4c0..a0e5ca080bd 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -23,6 +23,7 @@ use acvm::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, MemoryAddress, Opcode as BrilligOpcode, Value, ValueOrArray, }, + brillig_vm::brillig::HeapValueType, FieldElement, }; use debug_show::DebugShow; @@ -41,7 +42,7 @@ pub(crate) const BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE: u32 = 127; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -131,7 +132,7 @@ impl BrilligContext { size: usize, ) { // debug_show handled by allocate_array_instruction - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.allocate_array_instruction(pointer_register, size_register); self.deallocate_register(size_register); } @@ -174,7 +175,7 @@ impl BrilligContext { ) { self.debug_show.allocate_instruction(pointer_register); // A variable can be stored in up to three values, so we reserve three values for that. - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.push_opcode(BrilligOpcode::Mov { destination: pointer_register, source: ReservedRegisters::stack_pointer(), @@ -286,7 +287,7 @@ impl BrilligContext { where F: FnOnce(&mut BrilligContext, MemoryAddress), { - let iterator_register = self.make_constant(0_u128.into()); + let iterator_register = self.make_usize_constant(0_u128.into()); let (loop_section, loop_label) = self.reserve_next_section_label(); self.enter_section(loop_section); @@ -500,6 +501,17 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Mov { destination, source }); } + /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. + pub(crate) fn cast_instruction( + &mut self, + destination: MemoryAddress, + source: MemoryAddress, + bit_size: u32, + ) { + self.debug_show.cast_instruction(destination, source, bit_size); + self.push_opcode(BrilligOpcode::Cast { destination, source, bit_size }); + } + /// Processes a binary instruction according `operation`. /// /// This method will compute lhs rhs @@ -529,9 +541,18 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: MemoryAddress, constant: Value) { + pub(crate) fn const_instruction( + &mut self, + result: MemoryAddress, + constant: Value, + bit_size: u32, + ) { self.debug_show.const_instruction(result, constant); - self.push_opcode(BrilligOpcode::Const { destination: result, value: constant }); + self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); + } + + pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { + self.const_instruction(result, constant, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); } /// Processes a not instruction. @@ -548,7 +569,7 @@ impl BrilligContext { // Compile !x as ((-1) - x) let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128)) - FieldElement::one(); - let max = self.make_constant(Value::from(u_max)); + let max = self.make_constant(Value::from(u_max), bit_size); let opcode = BrilligOpcode::BinaryIntOp { destination: result, op: BinaryIntOp::Sub, @@ -568,13 +589,19 @@ impl BrilligContext { &mut self, func_name: String, inputs: &[ValueOrArray], + input_value_types: &[HeapValueType], outputs: &[ValueOrArray], + output_value_types: &[HeapValueType], ) { + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), }; self.push_opcode(opcode); } @@ -704,7 +731,7 @@ impl BrilligContext { // The brillig VM performs all arithmetic operations modulo 2**bit_size // So to truncate any value to a target bit size we can just issue a no-op arithmetic operation // With bit size equal to target_bit_size - let zero_register = self.make_constant(Value::from(FieldElement::zero())); + let zero_register = self.make_constant(Value::from(FieldElement::zero()), bit_size); self.binary_instruction( value_to_truncate, zero_register, @@ -721,9 +748,16 @@ impl BrilligContext { } /// Returns a register which holds the value of a constant - pub(crate) fn make_constant(&mut self, constant: Value) -> MemoryAddress { + pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> MemoryAddress { + let register = self.allocate_register(); + self.const_instruction(register, constant, bit_size); + register + } + + /// Returns a register which holds the value of an usize constant + pub(crate) fn make_usize_constant(&mut self, constant: Value) -> MemoryAddress { let register = self.allocate_register(); - self.const_instruction(register, constant); + self.usize_const(register, constant); register } @@ -856,7 +890,7 @@ impl BrilligContext { op: BinaryIntOp, constant: usize, ) { - let const_register = self.make_constant(Value::from(constant)); + let const_register = self.make_usize_constant(Value::from(constant)); self.memory_op(operand, const_register, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_register(const_register); @@ -926,13 +960,13 @@ impl BrilligContext { /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { - let size_register = self.make_constant(array.size.into()); + let size_register = self.make_usize_constant(array.size.into()); BrilligVector { size: size_register, pointer: array.pointer, rc: array.rc } } /// Issues a blackbox operation. pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(op); + self.debug_show.black_box_op_instruction(&op); self.push_opcode(BrilligOpcode::BlackBox(op)); } @@ -947,7 +981,7 @@ impl BrilligContext { big_endian: bool, ) { self.mov_instruction(target_vector.size, limb_count); - self.const_instruction(target_vector.rc, 1_usize.into()); + self.usize_const(target_vector.rc, 1_usize.into()); self.allocate_array_instruction(target_vector.pointer, target_vector.size); let shifted_register = self.allocate_register(); @@ -1047,6 +1081,7 @@ pub(crate) mod tests { BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, ValueOrArray, }; + use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; @@ -1148,18 +1183,20 @@ pub(crate) mod tests { let mut context = BrilligContext::new(true); let r_stack = ReservedRegisters::stack_pointer(); // Start stack pointer at 0 - context.const_instruction(r_stack, Value::from(ReservedRegisters::len() + 3)); + context.usize_const(r_stack, Value::from(ReservedRegisters::len() + 3)); let r_input_size = MemoryAddress::from(ReservedRegisters::len()); let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); - context.const_instruction(r_input_size, Value::from(12_usize)); + context.usize_const(r_input_size, Value::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( "make_number_sequence".into(), &[ValueOrArray::MemoryAddress(r_input_size)], + &[HeapValueType::Simple], &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs index 437774da157..4ef8c9d1dfc 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs @@ -6,8 +6,11 @@ use crate::ssa::ir::dfg::CallStack; /// Represents a parameter or a return value of a function. #[derive(Debug, Clone)] pub(crate) enum BrilligParameter { - Simple, + /// A simple parameter or return value. Holds the bit size of the parameter. + Simple(u32), + /// An array parameter or return value. Holds the type of an array item and its size. Array(Vec, usize), + /// A slice parameter or return value. Holds the type of a slice item. Slice(Vec), } diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index b3fe30c40b4..856fb709fa9 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,6 +1,10 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, MemoryAddress, ValueOrArray}; +use acvm::brillig_vm::brillig::{ + HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +}; use serde::{Deserialize, Serialize}; +use crate::ssa::ir::types::Type; + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { @@ -93,3 +97,16 @@ impl BrilligVariable { } } } + +pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { + match typ { + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Array(elem_type, size) => HeapValueType::Array { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + size: typ.element_size() * size, + }, + Type::Slice(elem_type) => HeapValueType::Vector { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + }, + } +} diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 28359f8dcea..6ee2e0c0b9f 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -172,6 +172,22 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); } + /// Emits a `cast` instruction. + pub(crate) fn cast_instruction( + &self, + destination: MemoryAddress, + source: MemoryAddress, + bit_size: u32, + ) { + debug_println!( + self.enable_debug_trace, + " CAST {}, {} as u{}", + destination, + source, + bit_size + ); + } + /// Processes a binary instruction according `operation`. pub(crate) fn binary_instruction( &self, @@ -342,7 +358,7 @@ impl DebugShow { } /// Debug function for black_box_op - pub(crate) fn black_box_op_instruction(&self, op: BlackBoxOp) { + pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); @@ -457,7 +473,7 @@ impl DebugShow { output ); } - BlackBoxOp::BigIntNeg { lhs, rhs, output } => { + BlackBoxOp::BigIntSub { lhs, rhs, output } => { debug_println!( self.enable_debug_trace, " BIGINT_NEG {} {} -> {}", diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index b9d95788b80..0eb4c8c31bd 100644 --- a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -3,9 +3,12 @@ use super::{ brillig_variable::{BrilligArray, BrilligVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, - BrilligContext, ReservedRegisters, + BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, +}; +use acvm::{ + acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, + FieldElement, }; -use acvm::acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}; pub(crate) const MAX_STACK_SIZE: usize = 1024; @@ -48,14 +51,11 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Const { destination: ReservedRegisters::stack_pointer(), value: (MAX_STACK_SIZE + calldata_size + return_data_size).into(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }); // Copy calldata - self.push_opcode(BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(MAX_STACK_SIZE), - size: calldata_size, - offset: 0, - }); + self.copy_and_cast_calldata(arguments); // Allocate the variables for every argument: let mut current_calldata_pointer = MAX_STACK_SIZE; @@ -63,7 +63,7 @@ impl BrilligContext { let mut argument_variables: Vec<_> = arguments .iter() .map(|argument| match argument { - BrilligParameter::Simple => { + BrilligParameter::Simple(_) => { let simple_address = self.allocate_register(); let var = BrilligVariable::Simple(simple_address); self.mov_instruction(simple_address, MemoryAddress(current_calldata_pointer)); @@ -72,8 +72,8 @@ impl BrilligContext { } BrilligParameter::Array(_, _) => { let pointer_to_the_array_in_calldata = - self.make_constant(current_calldata_pointer.into()); - let rc_register = self.make_constant(1_usize.into()); + self.make_usize_constant(current_calldata_pointer.into()); + let rc_register = self.make_usize_constant(1_usize.into()); let flattened_size = BrilligContext::flattened_size(argument); let var = BrilligVariable::BrilligArray(BrilligArray { pointer: pointer_to_the_array_in_calldata, @@ -106,10 +106,40 @@ impl BrilligContext { } } + fn copy_and_cast_calldata(&mut self, arguments: &[BrilligParameter]) { + let calldata_size = BrilligContext::flattened_tuple_size(arguments); + self.push_opcode(BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress(MAX_STACK_SIZE), + size: calldata_size, + offset: 0, + }); + + fn flat_bit_sizes(param: &BrilligParameter) -> Box + '_> { + match param { + BrilligParameter::Simple(bit_size) => Box::new(std::iter::once(*bit_size)), + BrilligParameter::Array(item_types, item_count) => Box::new( + (0..*item_count).flat_map(move |_| item_types.iter().flat_map(flat_bit_sizes)), + ), + BrilligParameter::Slice(..) => unimplemented!("Unsupported slices as parameter"), + } + } + + for (i, bit_size) in arguments.iter().flat_map(flat_bit_sizes).enumerate() { + // Calldatacopy tags everything with field type, so when downcast when necessary + if bit_size < FieldElement::max_num_bits() { + self.push_opcode(BrilligOpcode::Cast { + destination: MemoryAddress(MAX_STACK_SIZE + i), + source: MemoryAddress(MAX_STACK_SIZE + i), + bit_size, + }); + } + } + } + /// Computes the size of a parameter if it was flattened fn flattened_size(param: &BrilligParameter) -> usize { match param { - BrilligParameter::Simple => 1, + BrilligParameter::Simple(_) => 1, BrilligParameter::Array(item_types, item_count) => { let item_size: usize = item_types.iter().map(BrilligContext::flattened_size).sum(); item_count * item_size @@ -127,7 +157,7 @@ impl BrilligContext { /// Computes the size of a parameter if it was flattened fn has_nested_arrays(tuple: &[BrilligParameter]) -> bool { - tuple.iter().any(|param| !matches!(param, BrilligParameter::Simple)) + tuple.iter().any(|param| !matches!(param, BrilligParameter::Simple(_))) } /// Deflatten an array by recursively allocating nested arrays and copying the plain values. @@ -158,13 +188,13 @@ impl BrilligContext { for (subitem_index, subitem) in item_type.iter().enumerate() { let source_index = - self.make_constant((source_item_base_index + source_offset).into()); + self.make_usize_constant((source_item_base_index + source_offset).into()); let target_index = - self.make_constant((target_item_base_index + subitem_index).into()); + self.make_usize_constant((target_item_base_index + subitem_index).into()); match subitem { - BrilligParameter::Simple => { + BrilligParameter::Simple(_) => { self.array_get( flattened_array_pointer, source_index, @@ -196,7 +226,7 @@ impl BrilligContext { ); let reference = self.allocate_register(); let rc = self.allocate_register(); - self.const_instruction(rc, 1_usize.into()); + self.usize_const(rc, 1_usize.into()); self.allocate_array_reference_instruction(reference); let array_variable = BrilligVariable::BrilligArray(BrilligArray { @@ -249,7 +279,7 @@ impl BrilligContext { let returned_variables: Vec<_> = return_parameters .iter() .map(|return_parameter| match return_parameter { - BrilligParameter::Simple => BrilligVariable::Simple(self.allocate_register()), + BrilligParameter::Simple(_) => BrilligVariable::Simple(self.allocate_register()), BrilligParameter::Array(item_types, item_count) => { BrilligVariable::BrilligArray(BrilligArray { pointer: self.allocate_register(), @@ -271,7 +301,7 @@ impl BrilligContext { for (return_param, returned_variable) in return_parameters.iter().zip(&returned_variables) { match return_param { - BrilligParameter::Simple => { + BrilligParameter::Simple(_) => { self.mov_instruction( MemoryAddress(return_data_index), returned_variable.extract_register(), @@ -280,7 +310,7 @@ impl BrilligContext { } BrilligParameter::Array(item_type, item_count) => { let returned_pointer = returned_variable.extract_array().pointer; - let pointer_to_return_data = self.make_constant(return_data_index.into()); + let pointer_to_return_data = self.make_usize_constant(return_data_index.into()); self.flatten_array( item_type, @@ -324,12 +354,12 @@ impl BrilligContext { for (subitem_index, subitem) in item_type.iter().enumerate() { let source_index = - self.make_constant((source_item_base_index + subitem_index).into()); + self.make_usize_constant((source_item_base_index + subitem_index).into()); let target_index = - self.make_constant((target_item_base_index + target_offset).into()); + self.make_usize_constant((target_item_base_index + target_offset).into()); match subitem { - BrilligParameter::Simple => { + BrilligParameter::Simple(_) => { self.array_get( deflattened_array_pointer, source_index, @@ -405,7 +435,7 @@ impl BrilligContext { self.deallocate_register(movement_register); } else { - let item_count = self.make_constant((item_count * item_type.len()).into()); + let item_count = self.make_usize_constant((item_count * item_type.len()).into()); self.copy_array_instruction( deflattened_array_pointer, flattened_array_pointer, @@ -438,12 +468,12 @@ mod tests { ]; let arguments = vec![BrilligParameter::Array( vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], 2), - BrilligParameter::Simple, + BrilligParameter::Array(vec![BrilligParameter::Simple(8)], 2), + BrilligParameter::Simple(8), ], 2, )]; - let returns = vec![BrilligParameter::Simple]; + let returns = vec![BrilligParameter::Simple(8)]; let mut context = create_context(); @@ -476,8 +506,8 @@ mod tests { ]; let array_param = BrilligParameter::Array( vec![ - BrilligParameter::Array(vec![BrilligParameter::Simple], 2), - BrilligParameter::Simple, + BrilligParameter::Array(vec![BrilligParameter::Simple(8)], 2), + BrilligParameter::Simple(8), ], 2, ); diff --git a/noir/compiler/noirc_evaluator/src/ssa.rs b/noir/compiler/noirc_evaluator/src/ssa.rs index 108737f1f75..e1a2e0d3564 100644 --- a/noir/compiler/noirc_evaluator/src/ssa.rs +++ b/noir/compiler/noirc_evaluator/src/ssa.rs @@ -14,7 +14,7 @@ use crate::{ errors::{RuntimeError, SsaReport}, }; use acvm::acir::{ - circuit::{Circuit, PublicInputs}, + circuit::{Circuit, ExpressionWidth, PublicInputs}, native_types::Witness, }; @@ -107,6 +107,7 @@ pub fn create_circuit( let circuit = Circuit { current_witness_index, + expression_width: ExpressionWidth::Unbounded, opcodes, private_parameters, public_parameters, diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index f1a639de211..94e62e76746 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1199,7 +1199,7 @@ impl AcirContext { (vec![state_len], Vec::new()) } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv => { assert_eq!(inputs.len(), 4, "ICE - bigint operation requires 4 inputs"); @@ -1245,7 +1245,8 @@ impl AcirContext { for i in const_inputs { field_inputs.push(i?); } - let modulus = self.big_int_ctx.modulus(field_inputs[0]); + let bigint = self.big_int_ctx.get(field_inputs[0]); + let modulus = self.big_int_ctx.modulus(bigint.modulus_id()); let bytes_len = ((modulus - BigUint::from(1_u32)).bits() - 1) / 8 + 1; output_count = bytes_len as usize; (field_inputs, vec![FieldElement::from(bytes_len as u128)]) @@ -1452,10 +1453,8 @@ impl AcirContext { } Ok(BrilligInputs::Array(var_expressions)) } - AcirValue::DynamicArray(_) => { - let mut var_expressions = Vec::new(); - self.brillig_array_input(&mut var_expressions, i)?; - Ok(BrilligInputs::Array(var_expressions)) + AcirValue::DynamicArray(AcirDynamicArray { block_id, .. }) => { + Ok(BrilligInputs::MemoryArray(block_id)) } } })?; @@ -1869,6 +1868,9 @@ fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option { + return None; + } } } diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index b86fc4eeb5f..4d88a449e1c 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -252,7 +252,7 @@ impl GeneratedAcir { rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, }, - BlackBoxFunc::BigIntNeg => BlackBoxFuncCall::BigIntNeg { + BlackBoxFunc::BigIntSub => BlackBoxFuncCall::BigIntSub { lhs: constant_inputs[0].to_u128() as u32, rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, @@ -646,7 +646,7 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // Big integer operations take in 0 inputs. They use constants for their inputs. BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntToLeBytes => Some(0), @@ -696,7 +696,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Big integer operations return a big integer BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntFromLeBytes => Some(0), diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 0178ae9dba1..64f81e05f77 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -434,7 +434,7 @@ fn simplify_black_box_func( SimplifyResult::None } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::RecursiveAggregation diff --git a/noir/compiler/wasm/src/compile.rs b/noir/compiler/wasm/src/compile.rs index b39a27a7931..c8b1680bc00 100644 --- a/noir/compiler/wasm/src/compile.rs +++ b/noir/compiler/wasm/src/compile.rs @@ -177,7 +177,7 @@ pub fn compile( let compile_options = CompileOptions::default(); // For now we default to a bounded width of 3, though we can add it as a parameter - let expression_width = acvm::ExpressionWidth::Bounded { width: 3 }; + let expression_width = acvm::acir::circuit::ExpressionWidth::Bounded { width: 3 }; if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) diff --git a/noir/compiler/wasm/src/compile_new.rs b/noir/compiler/wasm/src/compile_new.rs index 4616004ae2b..f8fbed4f470 100644 --- a/noir/compiler/wasm/src/compile_new.rs +++ b/noir/compiler/wasm/src/compile_new.rs @@ -94,7 +94,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); @@ -120,7 +120,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); let compiled_contract = diff --git a/noir/noir_stdlib/src/bigint.nr b/noir/noir_stdlib/src/bigint.nr index 9edd59359c1..11026651207 100644 --- a/noir/noir_stdlib/src/bigint.nr +++ b/noir/noir_stdlib/src/bigint.nr @@ -1,5 +1,20 @@ use crate::ops::{Add, Sub, Mul, Div, Rem,}; + +global bn254_fq = [0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; +global bn254_fr = [0x01, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x1F, 0x43, 0x09, 0x97, 0xB9, 0x79, 0x48, 0xE8, 0x33, 0x28, + 0x5D, 0x58, 0x81, 0x81, 0xB6, 0x45, 0x50, 0xB8, 0x29, 0xA0, 0x31, 0xE1, 0x72, 0x4E, 0x64, 0x30]; +global secpk1_fr = [0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpk1_fq = [0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fq = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fr = [0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,0xFF, 0xFF, 0xFF, 0xFF]; + + struct BigInt { pointer: u32, modulus: u32, @@ -7,21 +22,34 @@ struct BigInt { impl BigInt { #[builtin(bigint_add)] - pub fn bigint_add(self, other: BigInt) -> BigInt { + fn bigint_add(self, other: BigInt) -> BigInt { } - #[builtin(bigint_neg)] - pub fn bigint_neg(self, other: BigInt) -> BigInt { + #[builtin(bigint_sub)] + fn bigint_sub(self, other: BigInt) -> BigInt { } #[builtin(bigint_mul)] - pub fn bigint_mul(self, other: BigInt) -> BigInt { + fn bigint_mul(self, other: BigInt) -> BigInt { } #[builtin(bigint_div)] - pub fn bigint_div(self, other: BigInt) -> BigInt { + fn bigint_div(self, other: BigInt) -> BigInt { } #[builtin(bigint_from_le_bytes)] - pub fn from_le_bytes(bytes: [u8], modulus: [u8]) -> BigInt {} + fn from_le_bytes(bytes: [u8], modulus: [u8]) -> BigInt {} #[builtin(bigint_to_le_bytes)] pub fn to_le_bytes(self) -> [u8] {} + + pub fn bn254_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fr) + } + pub fn bn254_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fq) + } + pub fn secpk1_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fq) + } + pub fn secpk1_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fr) + } } impl Add for BigInt { @@ -31,7 +59,7 @@ impl Add for BigInt { } impl Sub for BigInt { fn sub(self: Self, other: BigInt) -> BigInt { - self.bigint_neg(other) + self.bigint_sub(other) } } impl Mul for BigInt { @@ -47,7 +75,7 @@ impl Div for BigInt { impl Rem for BigInt { fn rem(self: Self, other: BigInt) -> BigInt { let quotient = self.bigint_div(other); - self.bigint_neg(quotient.bigint_mul(other)) + self.bigint_sub(quotient.bigint_mul(other)) } } diff --git a/noir/noir_stdlib/src/lib.nr b/noir/noir_stdlib/src/lib.nr index 5165d1ee07b..ebde4b88858 100644 --- a/noir/noir_stdlib/src/lib.nr +++ b/noir/noir_stdlib/src/lib.nr @@ -25,7 +25,7 @@ mod ops; mod default; mod prelude; mod uint128; -// mod bigint; +mod bigint; // Oracle calls are required to be wrapped in an unconstrained function // Thus, the only argument to the `println` oracle is expected to always be an ident diff --git a/noir/test_programs/execution_success/bigint/Nargo.toml b/noir/test_programs/execution_success/bigint/Nargo.toml new file mode 100644 index 00000000000..eee0920f188 --- /dev/null +++ b/noir/test_programs/execution_success/bigint/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "bigint" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/test_programs/execution_success/bigint/Prover.toml b/noir/test_programs/execution_success/bigint/Prover.toml new file mode 100644 index 00000000000..c50874a8613 --- /dev/null +++ b/noir/test_programs/execution_success/bigint/Prover.toml @@ -0,0 +1,2 @@ +x = [34,3,5,8,4] +y = [44,7,1,8,8] \ No newline at end of file diff --git a/noir/test_programs/execution_success/bigint/src/main.nr b/noir/test_programs/execution_success/bigint/src/main.nr new file mode 100644 index 00000000000..74949a5f785 --- /dev/null +++ b/noir/test_programs/execution_success/bigint/src/main.nr @@ -0,0 +1,21 @@ +use dep::std::bigint; + +fn main(mut x: [u8;5], y: [u8;5]) { + let a = bigint::BigInt::secpk1_fq_from_le_bytes([x[0],x[1],x[2],x[3],x[4]]); + let b = bigint::BigInt::secpk1_fq_from_le_bytes([y[0],y[1],y[2],y[3],y[4]]); + + let a_bytes = a.to_le_bytes(); + let b_bytes = b.to_le_bytes(); + for i in 0..5 { + assert(a_bytes[i] == x[i]); + assert(b_bytes[i] == y[i]); + } + + let d = a*b - b; + let d_bytes = d.to_le_bytes(); + let d1 = bigint::BigInt::secpk1_fq_from_le_bytes(597243850900842442924.to_le_bytes(10)); + let d1_bytes = d1.to_le_bytes(); + for i in 0..32 { + assert(d_bytes[i] == d1_bytes[i]); + } +} diff --git a/noir/test_programs/execution_success/debug_logs/src/main.nr b/noir/test_programs/execution_success/debug_logs/src/main.nr index 52c910065c1..cbce6f15286 100644 --- a/noir/test_programs/execution_success/debug_logs/src/main.nr +++ b/noir/test_programs/execution_success/debug_logs/src/main.nr @@ -50,6 +50,12 @@ fn main(x: Field, y: pub Field) { regression_2906(); + let first_array = [1, 2, 3]; + let second_array = [4, 5, 6]; + let arrays_nested = [first_array, second_array]; + std::println(f"first_array: {first_array}, second_array: {second_array}"); + std::println(f"arrays_nested: {arrays_nested}"); + let free_lambda = |x| x + 1; let sentinel: u32 = 8888; std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}"); diff --git a/noir/tooling/backend_interface/src/cli/info.rs b/noir/tooling/backend_interface/src/cli/info.rs index 934351dd517..8ca3d4dd0a3 100644 --- a/noir/tooling/backend_interface/src/cli/info.rs +++ b/noir/tooling/backend_interface/src/cli/info.rs @@ -1,4 +1,5 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; + use serde::Deserialize; use std::path::{Path, PathBuf}; diff --git a/noir/tooling/backend_interface/src/proof_system.rs b/noir/tooling/backend_interface/src/proof_system.rs index 9369c91fa94..485381006df 100644 --- a/noir/tooling/backend_interface/src/proof_system.rs +++ b/noir/tooling/backend_interface/src/proof_system.rs @@ -2,8 +2,10 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; -use acvm::ExpressionWidth; +use acvm::acir::{ + circuit::{Circuit, ExpressionWidth}, + native_types::WitnessMap, +}; use acvm::FieldElement; use tempfile::tempdir; use tracing::warn; diff --git a/noir/tooling/backend_interface/src/smart_contract.rs b/noir/tooling/backend_interface/src/smart_contract.rs index 524832c6308..5af75e48389 100644 --- a/noir/tooling/backend_interface/src/smart_contract.rs +++ b/noir/tooling/backend_interface/src/smart_contract.rs @@ -38,7 +38,7 @@ mod tests { use std::collections::BTreeSet; use acvm::acir::{ - circuit::{Circuit, Opcode, PublicInputs}, + circuit::{Circuit, ExpressionWidth, Opcode, PublicInputs}, native_types::{Expression, Witness}, }; @@ -51,6 +51,7 @@ mod tests { let circuit = Circuit { current_witness_index: 4, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes: vec![constraint], private_parameters: BTreeSet::from([Witness(1), Witness(2)]), public_parameters: PublicInputs::default(), diff --git a/noir/tooling/debugger/src/context.rs b/noir/tooling/debugger/src/context.rs index 8e5c1dacf2c..9c12794d5dd 100644 --- a/noir/tooling/debugger/src/context.rs +++ b/noir/tooling/debugger/src/context.rs @@ -432,7 +432,7 @@ mod tests { }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ - BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, + BinaryFieldOp, HeapValueType, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, }; use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; @@ -459,11 +459,14 @@ mod tests { BrilligOpcode::Const { destination: MemoryAddress::from(1), value: Value::from(fe_0), + bit_size: 32, }, BrilligOpcode::ForeignCall { function: "clear_mock".into(), destinations: vec![], + destination_value_types: vec![], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], diff --git a/noir/tooling/lsp/src/requests/profile_run.rs b/noir/tooling/lsp/src/requests/profile_run.rs index d866be8988b..917c247410d 100644 --- a/noir/tooling/lsp/src/requests/profile_run.rs +++ b/noir/tooling/lsp/src/requests/profile_run.rs @@ -3,7 +3,7 @@ use std::{ future::{self, Future}, }; -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; use nargo::{artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; diff --git a/noir/tooling/nargo/src/ops/transform.rs b/noir/tooling/nargo/src/ops/transform.rs index f3efd82333e..9267ed7e045 100644 --- a/noir/tooling/nargo/src/ops/transform.rs +++ b/noir/tooling/nargo/src/ops/transform.rs @@ -1,4 +1,4 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; diff --git a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs index 67322b1873e..f25d0ac212b 100644 --- a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,5 +1,5 @@ +use acvm::acir::circuit::ExpressionWidth; use acvm::acir::native_types::WitnessMap; -use acvm::ExpressionWidth; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; @@ -43,7 +43,10 @@ fn parse_expression_width(input: &str) -> Result() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } struct LoadError(&'static str); diff --git a/noir/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/tooling/nargo_cli/src/cli/info_cmd.rs index 131fd6ad214..ef0df0bf25b 100644 --- a/noir/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/tooling/nargo_cli/src/cli/info_cmd.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap; diff --git a/scripts/git-subrepo/Intro.pod b/scripts/git-subrepo/Intro.pod index a4d30716cc0..656c5f32e0a 100644 --- a/scripts/git-subrepo/Intro.pod +++ b/scripts/git-subrepo/Intro.pod @@ -78,7 +78,7 @@ Submodules tend to receive a lot of bad press. Here's some of it: =item * L -=item * L +=item * L =item * L diff --git a/scripts/git-subrepo/doc/intro-to-subrepo.swim b/scripts/git-subrepo/doc/intro-to-subrepo.swim index b4524ed21b0..286663159ed 100644 --- a/scripts/git-subrepo/doc/intro-to-subrepo.swim +++ b/scripts/git-subrepo/doc/intro-to-subrepo.swim @@ -61,7 +61,7 @@ article is about. Submodules tend to receive a lot of bad press. Here's some of it: * http://ayende.com/blog/4746/the-problem-with-git-submodules -* http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/ +* https://web.archive.org/web/20171101202911/http://somethingsinistral.net/blog/git-submodules-are-probably-not-the-answer/ * http://codingkilledthecat.wordpress.com/2012/04/28/why-your-company-shouldnt-use-git-submodules/ A quick recap of some of the good and bad things about submodules: diff --git a/scripts/git-subrepo/ext/bashplus/bin/bash+ b/scripts/git-subrepo/ext/bashplus/bin/bash+ index e0bc1f73913..a691460242d 100755 --- a/scripts/git-subrepo/ext/bashplus/bin/bash+ +++ b/scripts/git-subrepo/ext/bashplus/bin/bash+ @@ -5,7 +5,7 @@ # Copyright (c) 2013-2020 Ingy döt Net #------------------------------------------------------------------------------ -set -eu +set -e shopt -s compat31 &>/dev/null || true #------------------------------------------------------------------------------ diff --git a/scripts/git-subrepo/ext/bashplus/lib/bash+.bash b/scripts/git-subrepo/ext/bashplus/lib/bash+.bash index b52e17b55a6..dccdac08376 100644 --- a/scripts/git-subrepo/ext/bashplus/lib/bash+.bash +++ b/scripts/git-subrepo/ext/bashplus/lib/bash+.bash @@ -2,7 +2,7 @@ # # Copyright (c) 2013-2020 Ingy döt Net -set -eu +set -e [[ ${BASHPLUS_VERSION-} ]] && return 0 diff --git a/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+ b/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+ index e0bc1f73913..a691460242d 100755 --- a/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+ +++ b/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/bin/bash+ @@ -5,7 +5,7 @@ # Copyright (c) 2013-2020 Ingy döt Net #------------------------------------------------------------------------------ -set -eu +set -e shopt -s compat31 &>/dev/null || true #------------------------------------------------------------------------------ diff --git a/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/lib/bash+.bash b/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/lib/bash+.bash index e0e15cfc49d..2e1a70c2079 100644 --- a/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/lib/bash+.bash +++ b/scripts/git-subrepo/ext/test-more-bash/ext/bashplus/lib/bash+.bash @@ -2,7 +2,7 @@ # # Copyright (c) 2013-2020 Ingy döt Net -set -eu +set -e [[ ${BASHPLUS_VERSION-} ]] && return 0 diff --git a/scripts/git-subrepo/lib/git-subrepo.d/help-functions.bash b/scripts/git-subrepo/lib/git-subrepo.d/help-functions.bash index 98e34dd272b..123bb54cbb5 100644 --- a/scripts/git-subrepo/lib/git-subrepo.d/help-functions.bash +++ b/scripts/git-subrepo/lib/git-subrepo.d/help-functions.bash @@ -2,7 +2,7 @@ # DO NOT EDIT. This file generated by pkg/bin/generate-help-functions.pl. -set -eu +set -e help:all() { cat <<'...' diff --git a/scripts/git-subrepo/note/init-test b/scripts/git-subrepo/note/init-test index 810dae14a4d..a20854de88a 100755 --- a/scripts/git-subrepo/note/init-test +++ b/scripts/git-subrepo/note/init-test @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -ex cat $0 # Show this script in the output diff --git a/scripts/git-subrepo/note/recreate-rebase-conflict.sh b/scripts/git-subrepo/note/recreate-rebase-conflict.sh index 6dc0a51e300..21bf8365b75 100644 --- a/scripts/git-subrepo/note/recreate-rebase-conflict.sh +++ b/scripts/git-subrepo/note/recreate-rebase-conflict.sh @@ -1,6 +1,6 @@ -#!/usr/bin/env bash +#!/bin/bash -set -eu +set -e set -x # Make a directory to work in: diff --git a/scripts/git-subrepo/note/subtree-rebase-fail-example/test.bash b/scripts/git-subrepo/note/subtree-rebase-fail-example/test.bash index 9118236848a..df8b818cee6 100755 --- a/scripts/git-subrepo/note/subtree-rebase-fail-example/test.bash +++ b/scripts/git-subrepo/note/subtree-rebase-fail-example/test.bash @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -ex @@ -24,6 +24,6 @@ git clone repo1 repo3 git subrepo clone ../repo2 subrepo bash git rebase -i HEAD^ - git log -p + git log -p ls ) diff --git a/scripts/git-subrepo/note/test-subrepo-push.sh b/scripts/git-subrepo/note/test-subrepo-push.sh index 13b76e47fc8..afceb5efa92 100644 --- a/scripts/git-subrepo/note/test-subrepo-push.sh +++ b/scripts/git-subrepo/note/test-subrepo-push.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -ex diff --git a/scripts/git-subrepo/note/test.sh b/scripts/git-subrepo/note/test.sh index d27548f0937..fae278795d1 100755 --- a/scripts/git-subrepo/note/test.sh +++ b/scripts/git-subrepo/note/test.sh @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/bin/bash set -x diff --git a/scripts/git-subrepo/pkg/bin/generate-help-functions.pl b/scripts/git-subrepo/pkg/bin/generate-help-functions.pl index 5dd949e6ed9..40b6af8f2b3 100644 --- a/scripts/git-subrepo/pkg/bin/generate-help-functions.pl +++ b/scripts/git-subrepo/pkg/bin/generate-help-functions.pl @@ -33,7 +33,7 @@ sub write_start { # DO NOT EDIT. This file generated by pkg/bin/generate-help-functions.pl. -set -eu +set -e ... } diff --git a/yarn-project/Dockerfile b/yarn-project/Dockerfile index fcc719fefd1..dc2c7174abf 100644 --- a/yarn-project/Dockerfile +++ b/yarn-project/Dockerfile @@ -13,8 +13,9 @@ COPY . . RUN yarn workspace @aztec/noir-compiler build # Builds noir contracts (TODO: move this stage pre yarn-project). Generates typescript wrappers. RUN yarn workspace @aztec/noir-contracts build:contracts -# We need to build accounts as it needs to copy in account contracts from noir-contracts. +# We need to copy noir contracts into other packages RUN yarn workspace @aztec/accounts build:copy-contracts +RUN yarn workspace @aztec/protocol-contracts build:copy-contracts RUN yarn workspace @aztec/noir-protocol-circuits build RUN yarn tsc -b diff --git a/yarn-project/acir-simulator/src/avm/avm_context.test.ts b/yarn-project/acir-simulator/src/avm/avm_context.test.ts deleted file mode 100644 index 05e9cf10f3e..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_context.test.ts +++ /dev/null @@ -1,3 +0,0 @@ -describe('Avm', () => { - it('Executes a simple call', () => {}); -}); diff --git a/yarn-project/acir-simulator/src/avm/avm_context.ts b/yarn-project/acir-simulator/src/avm/avm_context.ts deleted file mode 100644 index b6226c818e9..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_context.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { AztecAddress, FunctionSelector } from '@aztec/circuits.js'; -import { Fr } from '@aztec/foundation/fields'; - -import { AvmExecutionEnvironment } from './avm_execution_environment.js'; -import { AvmMachineState } from './avm_machine_state.js'; -import { AvmMessageCallResult } from './avm_message_call_result.js'; -import { AvmInterpreterError, executeAvm } from './interpreter/index.js'; -import { AvmJournal } from './journal/journal.js'; -import { Instruction } from './opcodes/instruction.js'; -import { decodeFromBytecode } from './serialization/bytecode_serialization.js'; - -// FIXME: dependency cycle. - -/** - * Avm Executor manages the execution of the AVM - * - * It stores a state manager - */ -export class AvmContext { - /** Contains constant variables provided by the kernel */ - private executionEnvironment: AvmExecutionEnvironment; - /** Manages mutable state during execution - (caching, fetching) */ - private journal: AvmJournal; - - constructor(executionEnvironment: AvmExecutionEnvironment, journal: AvmJournal) { - this.executionEnvironment = executionEnvironment; - this.journal = journal; - } - - /** - * Call a contract with the given calldata - * - * - We get the contract from storage - * - We interpret the bytecode - * - We run the interpreter - * - */ - async call(): Promise { - // NOTE: the following is mocked as getPublicBytecode does not exist yet - const selector = new FunctionSelector(0); - const bytecode = await this.journal.hostStorage.contractsDb.getBytecode( - this.executionEnvironment.address, - selector, - ); - - // This assumes that we will not be able to send messages to accounts without code - // Pending classes and instances impl details - if (!bytecode) { - throw new NoBytecodeFoundInterpreterError(this.executionEnvironment.address); - } - - const instructions: Instruction[] = decodeFromBytecode(bytecode); - - const machineState = new AvmMachineState(this.executionEnvironment); - return executeAvm(machineState, this.journal, instructions); - } - - /** - * Create a new forked avm context - for internal calls - */ - public newWithForkedState(): AvmContext { - const forkedState = AvmJournal.branchParent(this.journal); - return new AvmContext(this.executionEnvironment, forkedState); - } - - /** - * Create a new forked avm context - for external calls - */ - public static newWithForkedState(executionEnvironment: AvmExecutionEnvironment, journal: AvmJournal): AvmContext { - const forkedState = AvmJournal.branchParent(journal); - return new AvmContext(executionEnvironment, forkedState); - } - - /** - * Prepare a new AVM context that will be ready for an external call - * - It will fork the journal - * - It will set the correct execution Environment Variables for a call - * - Alter both address and storageAddress - * - * @param address - The contract to call - * @param executionEnvironment - The current execution environment - * @param journal - The current journal - * @returns new AvmContext instance - */ - public static prepExternalCallContext( - address: AztecAddress, - calldata: Fr[], - executionEnvironment: AvmExecutionEnvironment, - journal: AvmJournal, - ): AvmContext { - const newExecutionEnvironment = executionEnvironment.newCall(address, calldata); - const forkedState = AvmJournal.branchParent(journal); - return new AvmContext(newExecutionEnvironment, forkedState); - } - - /** - * Prepare a new AVM context that will be ready for an external static call - * - It will fork the journal - * - It will set the correct execution Environment Variables for a call - * - Alter both address and storageAddress - * - * @param address - The contract to call - * @param executionEnvironment - The current execution environment - * @param journal - The current journal - * @returns new AvmContext instance - */ - public static prepExternalStaticCallContext( - address: AztecAddress, - calldata: Fr[], - executionEnvironment: AvmExecutionEnvironment, - journal: AvmJournal, - ): AvmContext { - const newExecutionEnvironment = executionEnvironment.newStaticCall(address, calldata); - const forkedState = AvmJournal.branchParent(journal); - return new AvmContext(newExecutionEnvironment, forkedState); - } - - /** - * Merge the journal of this call with it's parent - * NOTE: this should never be called on a root context - only from within a nested call - */ - public mergeJournalSuccess() { - this.journal.mergeSuccessWithParent(); - } - - /** - * Merge the journal of this call with it's parent - * For when the child call fails ( we still must track state accesses ) - */ - public mergeJournalFailure() { - this.journal.mergeFailureWithParent(); - } -} - -class NoBytecodeFoundInterpreterError extends AvmInterpreterError { - constructor(contractAddress: AztecAddress) { - super(`No bytecode found at: ${contractAddress}`); - this.name = 'NoBytecodeFoundInterpreterError'; - } -} diff --git a/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts b/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts deleted file mode 100644 index bf792862c8d..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_execution_environment.test.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { initExecutionEnvironment } from './fixtures/index.js'; - -describe('Execution Environment', () => { - const newAddress = new Fr(123456n); - const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - - it('New call should fork execution environment correctly', () => { - const executionEnvironment = initExecutionEnvironment(); - const newExecutionEnvironment = executionEnvironment.newCall(newAddress, calldata); - - allTheSameExcept(executionEnvironment, newExecutionEnvironment, { - address: newAddress, - storageAddress: newAddress, - calldata, - }); - }); - - it('New delegate call should fork execution environment correctly', () => { - const executionEnvironment = initExecutionEnvironment(); - const newExecutionEnvironment = executionEnvironment.newDelegateCall(newAddress, calldata); - - allTheSameExcept(executionEnvironment, newExecutionEnvironment, { - address: newAddress, - isDelegateCall: true, - calldata, - }); - }); - - it('New static call call should fork execution environment correctly', () => { - const executionEnvironment = initExecutionEnvironment(); - const newExecutionEnvironment = executionEnvironment.newStaticCall(newAddress, calldata); - - allTheSameExcept(executionEnvironment, newExecutionEnvironment, { - address: newAddress, - storageAddress: newAddress, - isStaticCall: true, - calldata, - }); - }); -}); - -/** - * Check all properties of one object are the same, except for the specified differentProperties - */ -function allTheSameExcept(referenceObject: any, comparingObject: any, differentProperties: Record): void { - for (const key in referenceObject) { - if (Object.keys(differentProperties).includes(key)) { - expect(comparingObject[key]).toEqual(differentProperties[key]); - } else { - expect(comparingObject[key]).toEqual(referenceObject[key]); - } - } -} diff --git a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts b/yarn-project/acir-simulator/src/avm/avm_machine_state.ts deleted file mode 100644 index 75da070f6b5..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_machine_state.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { AvmExecutionEnvironment } from './avm_execution_environment.js'; -import { TaggedMemory } from './avm_memory_types.js'; - -/** - * Store's data for an Avm execution frame - */ -export class AvmMachineState { - /** - * Execution environment contains hard coded information that is received from the kernel - * Items like, the block header and global variables fall within this category - */ - public readonly executionEnvironment: AvmExecutionEnvironment; - - private returnData: Fr[]; - - public readonly memory: TaggedMemory; - - /** - * When an internal_call is invoked, the internal call stack is added to with the current pc + 1 - * When internal_return is invoked, the latest value is popped from the internal call stack and set to the pc. - */ - public internalCallStack: number[]; - - public pc: number; - - public callStack: number[]; - - /** - * If an instruction triggers a halt, then it ends execution of the VM - */ - public halted: boolean; - /** - * Signifies if the execution has reverted ( due to a revert instruction ) - */ - public reverted: boolean; - - /** - * Create a new avm context - * @param executionEnvironment - Machine context that is passed to the avm - */ - constructor(executionEnvironment: AvmExecutionEnvironment) { - this.returnData = []; - this.memory = new TaggedMemory(); - this.internalCallStack = []; - - this.pc = 0; - this.callStack = []; - - this.halted = false; - this.reverted = false; - - this.executionEnvironment = executionEnvironment; - } - - /** - * Return data must NOT be modified once it is set - * @param returnData - - */ - public setReturnData(returnData: Fr[]) { - this.returnData = returnData; - Object.freeze(returnData); - } - - public getReturnData(): Fr[] { - return this.returnData; - } -} diff --git a/yarn-project/acir-simulator/src/avm/avm_memory_types.test.ts b/yarn-project/acir-simulator/src/avm/avm_memory_types.test.ts deleted file mode 100644 index 6df75930fe1..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_memory_types.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Field, Uint8 } from './avm_memory_types.js'; - -// TODO: complete -describe('Uint8', () => { - it('Unsigned 8 max value', () => { - expect(new Uint8(255).toBigInt()).toEqual(255n); - }); - - it('Unsigned 8 bit add', () => { - expect(new Uint8(50).add(new Uint8(20))).toEqual(new Uint8(70)); - }); - - it('Unsigned 8 bit add wraps', () => { - expect(new Uint8(200).add(new Uint8(100))).toEqual(new Uint8(44)); - }); -}); - -describe('Field', () => { - it('Add correctly without wrapping', () => { - expect(new Field(27).add(new Field(48))).toEqual(new Field(75)); - }); -}); diff --git a/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts b/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts deleted file mode 100644 index 713a306b3e9..00000000000 --- a/yarn-project/acir-simulator/src/avm/avm_message_call_result.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -/** - * AVM message call result. - */ -export class AvmMessageCallResult { - public readonly reverted: boolean; - - public readonly revertReason: Error | undefined; - /** .- */ - public readonly output: Fr[]; - - private constructor(reverted: boolean, output: Fr[], revertReason?: Error) { - this.reverted = reverted; - this.output = output; - this.revertReason = revertReason; - } - - /** - * Terminate a call as a success - * @param output - Return data - * @returns instance of AvmMessageCallResult - */ - public static success(output: Fr[]): AvmMessageCallResult { - return new AvmMessageCallResult(false, output); - } - - /** - * Terminate a call as a revert - * @param output - Return data ( revert message ) - * @param reason - Optional reason for revert - * @returns instance of AvmMessageCallResult - */ - public static revert(output: Fr[], reason?: Error): AvmMessageCallResult { - return new AvmMessageCallResult(true, output, reason); - } -} diff --git a/yarn-project/acir-simulator/src/avm/fixtures/index.ts b/yarn-project/acir-simulator/src/avm/fixtures/index.ts deleted file mode 100644 index 4c0d889063c..00000000000 --- a/yarn-project/acir-simulator/src/avm/fixtures/index.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Place large AVM text fixtures in here -import { GlobalVariables } from '@aztec/circuits.js'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { EthAddress } from '@aztec/foundation/eth-address'; -import { Fr } from '@aztec/foundation/fields'; - -import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; - -/** - * Create an empty instance of the Execution Environment where all values are zero, unless overriden in the overrides object - */ -export function initExecutionEnvironment(overrides?: Partial): AvmExecutionEnvironment { - return new AvmExecutionEnvironment( - overrides?.address ?? AztecAddress.zero(), - overrides?.storageAddress ?? AztecAddress.zero(), - overrides?.origin ?? AztecAddress.zero(), - overrides?.sender ?? AztecAddress.zero(), - overrides?.portal ?? EthAddress.ZERO, - overrides?.feePerL1Gas ?? Fr.zero(), - overrides?.feePerL2Gas ?? Fr.zero(), - overrides?.feePerDaGas ?? Fr.zero(), - overrides?.contractCallDepth ?? Fr.zero(), - overrides?.globals ?? GlobalVariables.empty(), - overrides?.isStaticCall ?? false, - overrides?.isDelegateCall ?? false, - overrides?.calldata ?? [], - ); -} - -/** - * Create an empty instance of the Execution Environment where all values are zero, unless overriden in the overrides object - */ -export function initGlobalVariables(overrides?: Partial): GlobalVariables { - return new GlobalVariables( - overrides?.chainId ?? Fr.zero(), - overrides?.version ?? Fr.zero(), - overrides?.blockNumber ?? Fr.zero(), - overrides?.timestamp ?? Fr.zero(), - ); -} diff --git a/yarn-project/acir-simulator/src/avm/index.test.ts b/yarn-project/acir-simulator/src/avm/index.test.ts deleted file mode 100644 index a9e05a97ea2..00000000000 --- a/yarn-project/acir-simulator/src/avm/index.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; -import { AvmTestContractArtifact } from '@aztec/noir-contracts'; - -import { mock } from 'jest-mock-extended'; - -import { AvmMachineState } from './avm_machine_state.js'; -import { TypeTag } from './avm_memory_types.js'; -import { initExecutionEnvironment } from './fixtures/index.js'; -import { executeAvm } from './interpreter/interpreter.js'; -import { AvmJournal } from './journal/journal.js'; -import { Add, CalldataCopy, Return } from './opcodes/index.js'; -import { decodeFromBytecode, encodeToBytecode } from './serialization/bytecode_serialization.js'; - -describe('avm', () => { - it('Should execute bytecode that performs basic addition', async () => { - const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const journal = mock(); - - // Construct bytecode - const bytecode = encodeToBytecode([ - new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 2, /*dstOffset=*/ 0), - new Add(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), - new Return(/*indirect=*/ 0, /*returnOffset=*/ 2, /*copySize=*/ 1), - ]); - - // Decode bytecode into instructions - const instructions = decodeFromBytecode(bytecode); - - // Execute instructions - const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const avmReturnData = await executeAvm(context, journal, instructions); - - expect(avmReturnData.reverted).toBe(false); - - const returnData = avmReturnData.output; - expect(returnData.length).toBe(1); - expect(returnData).toEqual([new Fr(3)]); - }); - - describe('testing transpiled Noir contracts', () => { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/4361): sync wire format w/transpiler. - it('Should execute contract function that performs addition', async () => { - const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const journal = mock(); - - // Get contract function artifact - const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_addArgsReturn')!; - - // Decode bytecode into instructions - const instructionsBytecode = Buffer.from(addArtifact.bytecode, 'base64'); - const instructions = decodeFromBytecode(instructionsBytecode); - - // Execute instructions - const context = new AvmMachineState(initExecutionEnvironment({ calldata })); - const avmReturnData = await executeAvm(context, journal, instructions); - - expect(avmReturnData.reverted).toBe(false); - - const returnData = avmReturnData.output; - expect(returnData.length).toBe(1); - expect(returnData).toEqual([new Fr(3)]); - }); - }); -}); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/index.ts b/yarn-project/acir-simulator/src/avm/interpreter/index.ts deleted file mode 100644 index d5189852b6e..00000000000 --- a/yarn-project/acir-simulator/src/avm/interpreter/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './interpreter.js'; diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts deleted file mode 100644 index c0111f067ac..00000000000 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; -import { TypeTag } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; -import { Add } from '../opcodes/arithmetic.js'; -import { Jump, Return } from '../opcodes/control_flow.js'; -import { Instruction } from '../opcodes/instruction.js'; -import { CalldataCopy } from '../opcodes/memory.js'; -import { InvalidProgramCounterError, executeAvm } from './interpreter.js'; - -describe('interpreter', () => { - let journal: MockProxy; - - beforeEach(() => { - journal = mock(); - }); - - it('Should execute a series of instructions', async () => { - const calldata: Fr[] = [new Fr(1), new Fr(2)]; - - const instructions: Instruction[] = [ - new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 2, /*dstOffset=*/ 0), - new Add(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), - new Return(/*indirect=*/ 0, /*returnOffset=*/ 2, /*copySize=*/ 1), - ]; - - const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - const avmReturnData = await executeAvm(machineState, journal, instructions); - - expect(avmReturnData.reverted).toBe(false); - expect(avmReturnData.revertReason).toBeUndefined(); - expect(avmReturnData.output).toEqual([new Fr(3)]); - }); - - it('Should revert with an invalid jump', async () => { - const calldata: Fr[] = []; - - const invalidJumpDestination = 22; - - const instructions: Instruction[] = [new Jump(invalidJumpDestination)]; - - const machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - const avmReturnData = await executeAvm(machineState, journal, instructions); - - expect(avmReturnData.reverted).toBe(true); - expect(avmReturnData.revertReason).toBeInstanceOf(InvalidProgramCounterError); - expect(avmReturnData.output).toHaveLength(0); - }); -}); diff --git a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts b/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts deleted file mode 100644 index fb23425f8b8..00000000000 --- a/yarn-project/acir-simulator/src/avm/interpreter/interpreter.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { strict as assert } from 'assert'; - -import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmMessageCallResult } from '../avm_message_call_result.js'; -import { AvmJournal } from '../journal/index.js'; -import { Instruction, InstructionExecutionError } from '../opcodes/instruction.js'; - -/** - * Run the avm - * @returns bool - successful execution will return true - * - reverted execution will return false - * - any other panic will throw - */ -export async function executeAvm( - machineState: AvmMachineState, - journal: AvmJournal, - instructions: Instruction[] = [], -): Promise { - assert(instructions.length > 0); - - try { - while (!machineState.halted) { - const instruction = instructions[machineState.pc]; - assert(!!instruction); // This should never happen - - await instruction.execute(machineState, journal); - - if (machineState.pc >= instructions.length) { - throw new InvalidProgramCounterError(machineState.pc, /*max=*/ instructions.length); - } - } - - const returnData = machineState.getReturnData(); - if (machineState.reverted) { - return AvmMessageCallResult.revert(returnData); - } - - return AvmMessageCallResult.success(returnData); - } catch (e) { - if (!(e instanceof AvmInterpreterError || e instanceof InstructionExecutionError)) { - throw e; - } - - const revertData = machineState.getReturnData(); - return AvmMessageCallResult.revert(revertData, /*revertReason=*/ e); - } -} - -/** - * Avm-specific errors should derive from this - */ -export abstract class AvmInterpreterError extends Error { - constructor(message: string, ...rest: any[]) { - super(message, ...rest); - this.name = 'AvmInterpreterError'; - } -} - -/** - * Error is thrown when the program counter goes to an invalid location. - * There is no instruction at the provided pc - */ -export class InvalidProgramCounterError extends AvmInterpreterError { - constructor(pc: number, max: number) { - super(`Invalid program counter ${pc}, max is ${max}`); - this.name = 'InvalidProgramCounterError'; - } -} diff --git a/yarn-project/acir-simulator/src/avm/journal/errors.ts b/yarn-project/acir-simulator/src/avm/journal/errors.ts deleted file mode 100644 index 17696b1de68..00000000000 --- a/yarn-project/acir-simulator/src/avm/journal/errors.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Error thrown when a base journal is attempted to be merged. - */ -export class RootJournalCannotBeMerged extends Error { - constructor() { - super('Root journal cannot be merged'); - } -} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts b/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts deleted file mode 100644 index f30be9b5053..00000000000 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { AvmMachineState } from '../avm_machine_state.js'; -import { IntegralValue } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/index.js'; -import { Opcode } from '../serialization/instruction_serialization.js'; -import { Instruction } from './instruction.js'; -import { ThreeOperandInstruction, TwoOperandInstruction } from './instruction_impl.js'; - -export class And extends ThreeOperandInstruction { - static readonly type: string = 'AND'; - static readonly opcode = Opcode.AND; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.getAs(this.aOffset); - const b = machineState.memory.getAs(this.bOffset); - - const res = a.and(b); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class Or extends ThreeOperandInstruction { - static readonly type: string = 'OR'; - static readonly opcode = Opcode.OR; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.getAs(this.aOffset); - const b = machineState.memory.getAs(this.bOffset); - - const res = a.or(b); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class Xor extends ThreeOperandInstruction { - static readonly type: string = 'XOR'; - static readonly opcode = Opcode.XOR; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.getAs(this.aOffset); - const b = machineState.memory.getAs(this.bOffset); - - const res = a.xor(b); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class Not extends TwoOperandInstruction { - static readonly type: string = 'NOT'; - static readonly opcode = Opcode.NOT; - - constructor(indirect: number, inTag: number, aOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset); - - const a = machineState.memory.getAs(this.aOffset); - - const res = a.not(); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class Shl extends ThreeOperandInstruction { - static readonly type: string = 'SHL'; - static readonly opcode = Opcode.SHL; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.getAs(this.aOffset); - const b = machineState.memory.getAs(this.bOffset); - - const res = a.shl(b); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class Shr extends ThreeOperandInstruction { - static readonly type: string = 'SHR'; - static readonly opcode = Opcode.SHR; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.getAs(this.aOffset); - const b = machineState.memory.getAs(this.bOffset); - - const res = a.shr(b); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts b/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts deleted file mode 100644 index a4cffa19d4a..00000000000 --- a/yarn-project/acir-simulator/src/avm/opcodes/comparators.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmJournal } from '../journal/index.js'; -import { Opcode } from '../serialization/instruction_serialization.js'; -import { Instruction } from './instruction.js'; -import { ThreeOperandInstruction } from './instruction_impl.js'; - -export class Eq extends ThreeOperandInstruction { - static readonly type: string = 'EQ'; - static readonly opcode = Opcode.EQ; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); - - // Result will be of the same type as 'a'. - const dest = a.build(a.equals(b) ? 1n : 0n); - machineState.memory.set(this.dstOffset, dest); - - this.incrementPc(machineState); - } -} - -export class Lt extends ThreeOperandInstruction { - static readonly type: string = 'LT'; - static readonly opcode = Opcode.LT; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); - - // Result will be of the same type as 'a'. - const dest = a.build(a.lt(b) ? 1n : 0n); - machineState.memory.set(this.dstOffset, dest); - - this.incrementPc(machineState); - } -} - -export class Lte extends ThreeOperandInstruction { - static readonly type: string = 'LTE'; - static readonly opcode = Opcode.LTE; - - constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { - super(indirect, inTag, aOffset, bOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - Instruction.checkTags(machineState, this.inTag, this.aOffset, this.bOffset); - - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); - - // Result will be of the same type as 'a'. - const dest = a.build(a.equals(b) || a.lt(b) ? 1n : 0n); - machineState.memory.set(this.dstOffset, dest); - - this.incrementPc(machineState); - } -} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/environment_getters.test.ts b/yarn-project/acir-simulator/src/avm/opcodes/environment_getters.test.ts deleted file mode 100644 index 2acf4729546..00000000000 --- a/yarn-project/acir-simulator/src/avm/opcodes/environment_getters.test.ts +++ /dev/null @@ -1,279 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; -import { initExecutionEnvironment, initGlobalVariables } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; -import { - Address, - BlockNumber, - ChainId, - FeePerDAGas, - FeePerL1Gas, - FeePerL2Gas, - Origin, - Portal, - Sender, - StorageAddress, - Timestamp, - Version, -} from './environment_getters.js'; - -describe('Environment getters instructions', () => { - let machineState: AvmMachineState; - let journal: MockProxy; - - beforeEach(async () => { - journal = mock(); - }); - - type EnvInstruction = Portal | FeePerL1Gas | FeePerL2Gas | FeePerDAGas | Origin | Sender | StorageAddress | Address; - const envGetterTest = async (key: string, value: Fr, instruction: EnvInstruction) => { - machineState = new AvmMachineState(initExecutionEnvironment({ [key]: value })); - - await instruction.execute(machineState, journal); - const actual = machineState.memory.get(0).toFr(); - expect(actual).toEqual(value); - }; - - describe('Address', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Address.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Address(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Address.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read address correctly', async () => { - const address = new Fr(123456n); - await envGetterTest('address', address, new Address(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('StorageAddress', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - StorageAddress.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new StorageAddress(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(StorageAddress.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read storage address correctly', async () => { - const address = new Fr(123456n); - await envGetterTest('storageAddress', address, new StorageAddress(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('Portal', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Portal.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Portal(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Portal.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read Portal correctly', async () => { - const portal = new Fr(123456n); - await envGetterTest('portal', portal, new Portal(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('FeePerL1Gas', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - FeePerL1Gas.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new FeePerL1Gas(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(FeePerL1Gas.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read FeePerL1Gas correctly', async () => { - const feePerL1Gas = new Fr(123456n); - await envGetterTest('feePerL1Gas', feePerL1Gas, new FeePerL1Gas(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('FeePerL2Gas', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - FeePerL2Gas.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new FeePerL2Gas(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(FeePerL2Gas.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read FeePerL2Gas correctly', async () => { - const feePerL2Gas = new Fr(123456n); - await envGetterTest('feePerL2Gas', feePerL2Gas, new FeePerL2Gas(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('FeePerDAGas', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - FeePerDAGas.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new FeePerDAGas(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(FeePerDAGas.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read FeePerDAGas correctly', async () => { - const feePerDaGas = new Fr(123456n); - await envGetterTest('feePerDaGas', feePerDaGas, new FeePerDAGas(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('Origin', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Origin.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Origin(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Origin.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read Origin correctly', async () => { - const origin = new Fr(123456n); - await envGetterTest('origin', origin, new Origin(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('Sender', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Sender.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Sender(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Sender.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read Sender correctly', async () => { - const sender = new Fr(123456n); - await envGetterTest('sender', sender, new Sender(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('Global Variables', () => { - type GlobalsInstruction = ChainId | Version | BlockNumber | Timestamp; - const readGlobalVariableTest = async (key: string, value: Fr, instruction: GlobalsInstruction) => { - const globals = initGlobalVariables({ [key]: value }); - machineState = new AvmMachineState(initExecutionEnvironment({ globals })); - - await instruction.execute(machineState, journal); - const actual = machineState.memory.get(0).toFr(); - expect(actual).toEqual(value); - }; - - describe('chainId', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - ChainId.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new ChainId(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(ChainId.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read chainId', async () => { - const chainId = new Fr(123456n); - await readGlobalVariableTest('chainId', chainId, new ChainId(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('version', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Version.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Version(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Version.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read version', async () => { - const version = new Fr(123456n); - await readGlobalVariableTest('version', version, new Version(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('block', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - BlockNumber.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new BlockNumber(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(BlockNumber.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read block number', async () => { - const blockNumber = new Fr(123456n); - await readGlobalVariableTest('blockNumber', blockNumber, new BlockNumber(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - - describe('timestamp', () => { - it('Should (de)serialize correctly', () => { - const buf = Buffer.from([ - Timestamp.opcode, // opcode - 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // dstOffset - ]); - const inst = new Timestamp(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); - - expect(Timestamp.deserialize(buf)).toEqual(inst); - expect(inst.serialize()).toEqual(buf); - }); - - it('Should read timestamp', async () => { - const timestamp = new Fr(123456n); - await readGlobalVariableTest('timestamp', timestamp, new Timestamp(/*indirect=*/ 0, /*dstOffset=*/ 0)); - }); - }); - }); -}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts b/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts deleted file mode 100644 index ff5fdd5e96f..00000000000 --- a/yarn-project/acir-simulator/src/avm/opcodes/instruction.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { assert } from 'console'; - -import { AvmMachineState } from '../avm_machine_state.js'; -import { TypeTag } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/index.js'; -import { BufferCursor } from '../serialization/buffer_cursor.js'; -import { OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js'; - -/** - * Parent class for all AVM instructions. - * It's most important aspects are execution and (de)serialization. - */ -export abstract class Instruction { - public abstract execute(machineState: AvmMachineState, journal: AvmJournal): Promise; - - incrementPc(machineState: AvmMachineState): void { - machineState.pc++; - } - - halt(machineState: AvmMachineState): void { - machineState.halted = true; - } - - revert(machineState: AvmMachineState): void { - machineState.halted = true; - machineState.reverted = true; - } - - static checkTags(machineState: AvmMachineState, tag: TypeTag, ...offsets: number[]) { - for (const offset of offsets) { - checkTag(machineState, tag, offset); - } - } - - static checkTagsRange(machineState: AvmMachineState, tag: TypeTag, startOffset: number, size: number) { - for (let offset = startOffset; offset < startOffset + size; offset++) { - checkTag(machineState, tag, offset); - } - } - - /** - * Deserializes a subclass of Instruction from a Buffer. - * If you want to use this, your subclass should specify a {@code static wireFormat: OperandType[]}. - * @param this Class object to deserialize to. - * @param buf Buffer to read from. - * @returns Constructed instance of Class. - */ - public static deserialize; wireFormat: OperandType[] }>( - this: T, - buf: BufferCursor | Buffer, - ): InstanceType { - const res = deserialize(buf, this.wireFormat); - const args = res.slice(1) as ConstructorParameters; // Remove opcode. - return new this(...args); - } - - public serialize(this: any): Buffer { - assert(this instanceof Instruction); - return serialize(this.constructor.wireFormat, this); - } -} - -/** - * Checks that the memory at the given offset has the given tag. - */ -function checkTag(machineState: AvmMachineState, tag: TypeTag, offset: number) { - if (machineState.memory.getTag(offset) !== tag) { - const error = `Offset ${offset} has tag ${TypeTag[machineState.memory.getTag(offset)]}, expected ${TypeTag[tag]}`; - throw new InstructionExecutionError(error); - } -} - -export class InstructionExecutionError extends Error { - constructor(message: string) { - super(message); - this.name = 'InstructionExecutionError'; - } -} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts b/yarn-project/acir-simulator/src/avm/opcodes/memory.ts deleted file mode 100644 index fd26f92060c..00000000000 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.ts +++ /dev/null @@ -1,141 +0,0 @@ -import { AvmMachineState } from '../avm_machine_state.js'; -import { Field, TaggedMemory, TypeTag } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/index.js'; -import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; -import { Instruction, InstructionExecutionError } from './instruction.js'; -import { TwoOperandInstruction } from './instruction_impl.js'; - -export class Set extends Instruction { - static readonly type: string = 'SET'; - static readonly opcode: Opcode = Opcode.SET; - // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [ - OperandType.UINT8, - OperandType.UINT8, - OperandType.UINT8, - OperandType.UINT128, - OperandType.UINT32, - ]; - - constructor(private indirect: number, private inTag: number, private value: bigint, private dstOffset: number) { - super(); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - // Per the YP, the tag cannot be a field. - if ([TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID].includes(this.inTag)) { - throw new InstructionExecutionError(`Invalid tag ${TypeTag[this.inTag]} for SET.`); - } - - const res = TaggedMemory.integralFromTag(this.value, this.inTag); - machineState.memory.set(this.dstOffset, res); - - this.incrementPc(machineState); - } -} - -export class CMov extends Instruction { - static readonly type: string = 'CMOV'; - static readonly opcode: Opcode = Opcode.CMOV; - // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [ - OperandType.UINT8, - OperandType.UINT8, - OperandType.UINT32, - OperandType.UINT32, - OperandType.UINT32, - OperandType.UINT32, - ]; - - constructor( - private indirect: number, - private aOffset: number, - private bOffset: number, - private condOffset: number, - private dstOffset: number, - ) { - super(); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); - const cond = machineState.memory.get(this.condOffset); - - // TODO: reconsider toBigInt() here - machineState.memory.set(this.dstOffset, cond.toBigInt() > 0 ? a : b); - - this.incrementPc(machineState); - } -} - -export class Cast extends TwoOperandInstruction { - static readonly type: string = 'CAST'; - static readonly opcode = Opcode.CAST; - - constructor(indirect: number, dstTag: number, aOffset: number, dstOffset: number) { - super(indirect, dstTag, aOffset, dstOffset); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - - // TODO: consider not using toBigInt() - const casted = - this.inTag == TypeTag.FIELD ? new Field(a.toBigInt()) : TaggedMemory.integralFromTag(a.toBigInt(), this.inTag); - - machineState.memory.set(this.dstOffset, casted); - - this.incrementPc(machineState); - } -} - -export class Mov extends Instruction { - static readonly type: string = 'MOV'; - static readonly opcode: Opcode = Opcode.MOV; - // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [ - OperandType.UINT8, - OperandType.UINT8, - OperandType.UINT32, - OperandType.UINT32, - ]; - - constructor(private indirect: number, private srcOffset: number, private dstOffset: number) { - super(); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.srcOffset); - - machineState.memory.set(this.dstOffset, a); - - this.incrementPc(machineState); - } -} - -export class CalldataCopy extends Instruction { - static readonly type: string = 'CALLDATACOPY'; - static readonly opcode: Opcode = Opcode.CALLDATACOPY; - // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat: OperandType[] = [ - OperandType.UINT8, - OperandType.UINT8, - OperandType.UINT32, - OperandType.UINT32, - OperandType.UINT32, - ]; - - constructor(private indirect: number, private cdOffset: number, private copySize: number, private dstOffset: number) { - super(); - } - - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const transformedData = machineState.executionEnvironment.calldata - .slice(this.cdOffset, this.cdOffset + this.copySize) - .map(f => new Field(f)); - machineState.memory.setSlice(this.dstOffset, transformedData); - - this.incrementPc(machineState); - } -} diff --git a/yarn-project/acir-simulator/src/utils.ts b/yarn-project/acir-simulator/src/utils.ts deleted file mode 100644 index b40f389bac8..00000000000 --- a/yarn-project/acir-simulator/src/utils.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { GrumpkinPrivateKey } from '@aztec/circuits.js'; -import { Grumpkin } from '@aztec/circuits.js/barretenberg'; -import { pedersenHash } from '@aztec/foundation/crypto'; -import { Fr } from '@aztec/foundation/fields'; - -/** - * A point in the format that Aztec.nr uses. - */ -export type NoirPoint = { - /** The x coordinate. */ - x: bigint; - /** The y coordinate. */ - y: bigint; -}; - -/** - * Computes the resulting storage slot for an entry in a mapping. - * @param mappingSlot - The slot of the mapping within state. - * @param owner - The key of the mapping. - * @returns The slot in the contract storage where the value is stored. - */ -export function computeSlotForMapping(mappingSlot: Fr, owner: NoirPoint | Fr) { - const isFr = (owner: NoirPoint | Fr): owner is Fr => typeof (owner as Fr).value === 'bigint'; - const ownerField = isFr(owner) ? owner : new Fr(owner.x); - - return Fr.fromBuffer(pedersenHash([mappingSlot, ownerField].map(f => f.toBuffer()))); -} - -/** - * Computes the public key for a private key. - * @param privateKey - The private key. - * @param grumpkin - The grumpkin instance. - * @returns The public key. - */ -export function toPublicKey(privateKey: GrumpkinPrivateKey, grumpkin: Grumpkin): NoirPoint { - const point = grumpkin.mul(Grumpkin.generator, privateKey); - return { - x: point.x.value, - y: point.y.value, - }; -} diff --git a/yarn-project/archiver/package.json b/yarn-project/archiver/package.json index 226a990ee5e..2612739365f 100644 --- a/yarn-project/archiver/package.json +++ b/yarn-project/archiver/package.json @@ -41,6 +41,7 @@ "@aztec/foundation": "workspace:^", "@aztec/kv-store": "workspace:^", "@aztec/l1-artifacts": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@aztec/types": "workspace:^", "debug": "^4.3.4", "lmdb": "^2.9.2", diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 4856a608bdf..b0568277d7d 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -14,18 +14,28 @@ import { LogFilter, LogType, TxHash, + UnencryptedL2Log, } from '@aztec/circuit-types'; -import { FunctionSelector, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; +import { + ContractClassRegisteredEvent, + FunctionSelector, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, +} from '@aztec/circuits.js'; +import { ContractInstanceDeployedEvent, computeSaltedInitializationHash } from '@aztec/circuits.js/contract'; import { createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { padArrayEnd } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; +import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; +import { InstanceDeployerAddress } from '@aztec/protocol-contracts/instance-deployer'; import { ContractClass, - ContractClassWithId, + ContractClassPublic, ContractInstance, ContractInstanceWithAddress, } from '@aztec/types/contracts'; @@ -63,6 +73,12 @@ export class Archiver implements ArchiveSource { */ private lastLoggedL1BlockNumber = 0n; + /** Address of the ClassRegisterer contract with a salt=1 */ + private classRegistererAddress = ClassRegistererAddress; + + /** Address of the InstanceDeployer contract with a salt=1 */ + private instanceDeployerAddress = InstanceDeployerAddress; + /** * Creates a new instance of the Archiver. * @param publicClient - A client for interacting with the Ethereum node. @@ -272,6 +288,17 @@ export class Archiver implements ArchiveSource { ), ); + // Unroll all logs emitted during the retrieved blocks and extract any contract classes and instances from them + await Promise.all( + retrievedBlocks.retrievedData.map(async block => { + const blockLogs = (block.newUnencryptedLogs?.txLogs ?? []) + .flatMap(txLog => txLog.unrollLogs()) + .map(log => UnencryptedL2Log.fromBuffer(log)); + await this.storeRegisteredContractClasses(blockLogs, block.number); + await this.storeDeployedContractInstances(blockLogs, block.number); + }), + ); + // store contracts for which we have retrieved L2 blocks const lastKnownL2BlockNum = retrievedBlocks.retrievedData[retrievedBlocks.retrievedData.length - 1].number; await Promise.all( @@ -302,6 +329,60 @@ export class Archiver implements ArchiveSource { ); } + /** + * Extracts and stores contract classes out of ContractClassRegistered events emitted by the class registerer contract. + * @param allLogs - All logs emitted in a bunch of blocks. + */ + private async storeRegisteredContractClasses(allLogs: UnencryptedL2Log[], blockNum: number) { + const contractClasses: ContractClassPublic[] = []; + for (const log of allLogs) { + try { + if ( + !log.contractAddress.equals(this.classRegistererAddress) || + toBigIntBE(log.data.subarray(0, 32)) !== REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE + ) { + continue; + } + const event = ContractClassRegisteredEvent.fromLogData(log.data); + contractClasses.push(event.toContractClassPublic()); + } catch (err) { + this.log.warn(`Error processing log ${log.toHumanReadable()}: ${err}`); + } + } + + if (contractClasses.length > 0) { + contractClasses.forEach(c => this.log(`Registering contract class ${c.id.toString()}`)); + await this.store.addContractClasses(contractClasses, blockNum); + } + } + + /** + * Extracts and stores contract instances out of ContractInstanceDeployed events emitted by the canonical deployer contract. + * @param allLogs - All logs emitted in a bunch of blocks. + */ + private async storeDeployedContractInstances(allLogs: UnencryptedL2Log[], blockNum: number) { + const contractInstances: ContractInstanceWithAddress[] = []; + for (const log of allLogs) { + try { + if ( + !log.contractAddress.equals(this.instanceDeployerAddress) || + !ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log.data) + ) { + continue; + } + const event = ContractInstanceDeployedEvent.fromLogData(log.data); + contractInstances.push(event.toContractInstance()); + } catch (err) { + this.log.warn(`Error processing log ${log.toHumanReadable()}: ${err}`); + } + } + + if (contractInstances.length > 0) { + contractInstances.forEach(c => this.log(`Storing contract instance at ${c.address.toString()}`)); + await this.store.addContractInstances(contractInstances, blockNum); + } + } + /** * Stores extended contract data as classes and instances. * Temporary solution until we source this data from the contract class registerer and instance deployer. @@ -373,8 +454,37 @@ export class Archiver implements ArchiveSource { * @param contractAddress - The contract data address. * @returns The extended contract data or undefined if not found. */ - getExtendedContractData(contractAddress: AztecAddress): Promise { - return this.store.getExtendedContractData(contractAddress); + public async getExtendedContractData(contractAddress: AztecAddress): Promise { + return ( + (await this.store.getExtendedContractData(contractAddress)) ?? this.makeExtendedContractDataFor(contractAddress) + ); + } + + /** + * Temporary method for creating a fake extended contract data out of classes and instances registered in the node. + * Used as a fallback if the extended contract data is not found. + */ + private async makeExtendedContractDataFor(address: AztecAddress): Promise { + const instance = await this.store.getContractInstance(address); + if (!instance) { + return undefined; + } + + const contractClass = await this.store.getContractClass(instance.contractClassId); + if (!contractClass) { + this.log.warn( + `Contract class ${instance.contractClassId.toString()} for address ${address.toString()} not found`, + ); + return undefined; + } + + return new ExtendedContractData( + new ContractData(address, instance.portalContractAddress), + contractClass.publicFunctions.map(f => new EncodedContractFunction(f.selector, f.isInternal, f.bytecode)), + contractClass.id, + computeSaltedInitializationHash(instance), + instance.publicKeysHash, + ); } /** @@ -448,6 +558,14 @@ export class Archiver implements ArchiveSource { return this.store.getBlockNumber(); } + public getContractClass(id: Fr): Promise { + return this.store.getContractClass(id); + } + + public getContract(address: AztecAddress): Promise { + return this.store.getContractInstance(address); + } + /** * Gets up to `limit` amount of pending L1 to L2 messages. * @param limit - The number of messages to return. @@ -475,7 +593,7 @@ export class Archiver implements ArchiveSource { */ function extendedContractDataToContractClassAndInstance( data: ExtendedContractData, -): [ContractClassWithId, ContractInstanceWithAddress] { +): [ContractClassPublic, ContractInstanceWithAddress] { const contractClass: ContractClass = { version: 1, artifactHash: Fr.ZERO, @@ -498,7 +616,7 @@ function extendedContractDataToContractClassAndInstance( }; const address = data.contractData.contractAddress; return [ - { ...contractClass, id: contractClassId }, + { ...contractClass, id: contractClassId, privateFunctionsRoot: Fr.ZERO }, { ...contractInstance, address }, ]; } diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index c8d033d40fd..06bc1ed5301 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -12,7 +12,7 @@ import { } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; /** * Represents the latest L1 block processed by the archiver for various objects in L2. @@ -175,13 +175,13 @@ export interface ArchiverDataStore { * @param blockNumber - Number of the L2 block the contracts were registered in. * @returns True if the operation is successful. */ - addContractClasses(data: ContractClassWithId[], blockNumber: number): Promise; + addContractClasses(data: ContractClassPublic[], blockNumber: number): Promise; /** * Returns a contract class given its id, or undefined if not exists. * @param id - Id of the contract class. */ - getContractClass(id: Fr): Promise; + getContractClass(id: Fr): Promise; /** * Add new contract instances from an L2 block to the store's list. diff --git a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts index 592addaefb0..b590b78a762 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -11,13 +11,9 @@ import { } from '@aztec/circuit-types'; import '@aztec/circuit-types/jest'; import { AztecAddress, Fr } from '@aztec/circuits.js'; +import { makeContractClassPublic } from '@aztec/circuits.js/factories'; import { randomBytes } from '@aztec/foundation/crypto'; -import { - ContractClassWithId, - ContractInstanceWithAddress, - SerializableContractClass, - SerializableContractInstance, -} from '@aztec/types/contracts'; +import { ContractClassPublic, ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; import { ArchiverDataStore } from './archiver_store.js'; @@ -345,11 +341,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); describe('contractClasses', () => { - let contractClass: ContractClassWithId; + let contractClass: ContractClassPublic; const blockNum = 10; beforeEach(async () => { - contractClass = { ...SerializableContractClass.random(), id: Fr.random() }; + contractClass = makeContractClassPublic(); await store.addContractClasses([contractClass], blockNum); }); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts index 686514aa1b7..79ededfb106 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts @@ -1,6 +1,7 @@ -import { Fr } from '@aztec/foundation/fields'; +import { Fr, FunctionSelector } from '@aztec/circuits.js'; +import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize'; import { AztecKVStore, AztecMap } from '@aztec/kv-store'; -import { ContractClassWithId, SerializableContractClass } from '@aztec/types/contracts'; +import { ContractClassPublic } from '@aztec/types/contracts'; /** * LMDB implementation of the ArchiverDataStore interface. @@ -12,15 +13,52 @@ export class ContractClassStore { this.#contractClasses = db.openMap('archiver_contract_classes'); } - addContractClass(contractClass: ContractClassWithId): Promise { - return this.#contractClasses.set( - contractClass.id.toString(), - new SerializableContractClass(contractClass).toBuffer(), - ); + addContractClass(contractClass: ContractClassPublic): Promise { + return this.#contractClasses.set(contractClass.id.toString(), serializeContractClassPublic(contractClass)); } - getContractClass(id: Fr): ContractClassWithId | undefined { + getContractClass(id: Fr): ContractClassPublic | undefined { const contractClass = this.#contractClasses.get(id.toString()); - return contractClass && SerializableContractClass.fromBuffer(contractClass).withId(id); + return contractClass && { ...deserializeContractClassPublic(contractClass), id }; } } + +export function serializeContractClassPublic(contractClass: ContractClassPublic): Buffer { + return serializeToBuffer( + numToUInt8(contractClass.version), + contractClass.artifactHash, + contractClass.privateFunctions?.length ?? 0, + contractClass.privateFunctions?.map(f => serializeToBuffer(f.selector, f.vkHash, f.isInternal)) ?? [], + contractClass.publicFunctions.length, + contractClass.publicFunctions?.map(f => + serializeToBuffer(f.selector, f.bytecode.length, f.bytecode, f.isInternal), + ) ?? [], + contractClass.packedBytecode.length, + contractClass.packedBytecode, + contractClass.privateFunctionsRoot, + ); +} + +export function deserializeContractClassPublic(buffer: Buffer): Omit { + const reader = BufferReader.asReader(buffer); + return { + version: reader.readUInt8() as 1, + artifactHash: reader.readObject(Fr), + privateFunctions: reader.readVector({ + fromBuffer: reader => ({ + selector: reader.readObject(FunctionSelector), + vkHash: reader.readObject(Fr), + isInternal: reader.readBoolean(), + }), + }), + publicFunctions: reader.readVector({ + fromBuffer: reader => ({ + selector: reader.readObject(FunctionSelector), + bytecode: reader.readBuffer(), + isInternal: reader.readBoolean(), + }), + }), + packedBytecode: reader.readBuffer(), + privateFunctionsRoot: reader.readObject(Fr), + }; +} diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts index 520ac236d05..90b3693716c 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.test.ts @@ -1,4 +1,4 @@ -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { describeArchiverDataStore } from '../archiver_store_test_suite.js'; import { KVArchiverDataStore } from './kv_archiver_store.js'; @@ -6,8 +6,8 @@ import { KVArchiverDataStore } from './kv_archiver_store.js'; describe('KVArchiverDataStore', () => { let archiverStore: KVArchiverDataStore; - beforeEach(async () => { - archiverStore = new KVArchiverDataStore(await AztecLmdbStore.openTmp()); + beforeEach(() => { + archiverStore = new KVArchiverDataStore(openTmpStore()); }); describeArchiverDataStore('ArchiverStore', () => archiverStore); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts index db9f0e4cddd..6b8339d09fc 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/kv_archiver_store.ts @@ -14,7 +14,7 @@ import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore } from '@aztec/kv-store'; -import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; import { BlockStore } from './block_store.js'; @@ -35,7 +35,7 @@ export class KVArchiverDataStore implements ArchiverDataStore { #contractClassStore: ContractClassStore; #contractInstanceStore: ContractInstanceStore; - #log = createDebugLogger('aztec:archiver:lmdb'); + #log = createDebugLogger('aztec:archiver:data-store'); constructor(db: AztecKVStore, logsMaxPageSize: number = 1000) { this.#blockStore = new BlockStore(db); @@ -46,7 +46,7 @@ export class KVArchiverDataStore implements ArchiverDataStore { this.#contractInstanceStore = new ContractInstanceStore(db); } - getContractClass(id: Fr): Promise { + getContractClass(id: Fr): Promise { return Promise.resolve(this.#contractClassStore.getContractClass(id)); } @@ -54,7 +54,7 @@ export class KVArchiverDataStore implements ArchiverDataStore { return Promise.resolve(this.#contractInstanceStore.getContractInstance(address)); } - async addContractClasses(data: ContractClassWithId[], _blockNumber: number): Promise { + async addContractClasses(data: ContractClassPublic[], _blockNumber: number): Promise { return (await Promise.all(data.map(c => this.#contractClassStore.addContractClass(c)))).every(Boolean); } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts index ecd0afda6d8..76ef94beb03 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.ts @@ -17,7 +17,7 @@ import { } from '@aztec/circuit-types'; import { Fr, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ArchiverDataStore } from '../archiver_store.js'; import { L1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_message_store.js'; @@ -69,7 +69,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ private pendingL1ToL2Messages: PendingL1ToL2MessageStore = new PendingL1ToL2MessageStore(); - private contractClasses: Map = new Map(); + private contractClasses: Map = new Map(); private contractInstances: Map = new Map(); @@ -81,7 +81,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { public readonly maxLogs: number, ) {} - public getContractClass(id: Fr): Promise { + public getContractClass(id: Fr): Promise { return Promise.resolve(this.contractClasses.get(id.toString())); } @@ -89,7 +89,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(this.contractInstances.get(address.toString())); } - public addContractClasses(data: ContractClassWithId[], _blockNumber: number): Promise { + public addContractClasses(data: ContractClassPublic[], _blockNumber: number): Promise { for (const contractClass of data) { this.contractClasses.set(contractClass.id.toString(), contractClass); } diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index 89b9c4bb127..c902d366f89 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -10,7 +10,7 @@ import { import { EthAddress, Fr } from '@aztec/circuits.js'; import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; -import { ArchiveSource } from '../index.js'; +import { ArchiveSource } from '../archiver/archiver.js'; export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], true)): ArchiveSource => createJsonRpcClient( diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index 7c011e5d242..a620e2925be 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -10,7 +10,7 @@ import { import { EthAddress, Fr } from '@aztec/circuits.js'; import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; -import { Archiver } from '../index.js'; +import { Archiver } from '../archiver/archiver.js'; /** * Wrap an Archiver instance with a JSON RPC HTTP server. diff --git a/yarn-project/archiver/tsconfig.json b/yarn-project/archiver/tsconfig.json index 69fe51229cc..08c5ba86b06 100644 --- a/yarn-project/archiver/tsconfig.json +++ b/yarn-project/archiver/tsconfig.json @@ -24,6 +24,9 @@ { "path": "../l1-artifacts" }, + { + "path": "../protocol-contracts" + }, { "path": "../types" } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 5f55ade4850..8e42de8e586 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -26,6 +26,7 @@ import { import { ARCHIVE_HEIGHT, CONTRACT_TREE_HEIGHT, + EthAddress, Fr, Header, L1_TO_L2_MSG_TREE_HEIGHT, @@ -39,7 +40,9 @@ import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/abis'; import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; +import { initStoreForRollup } from '@aztec/kv-store/utils'; import { AztecKVTxPool, P2P, createP2PClient } from '@aztec/p2p'; import { GlobalVariableBuilder, @@ -47,6 +50,7 @@ import { SequencerClient, getGlobalVariableBuilder, } from '@aztec/sequencer-client'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTrees, ServerWorldStateSynchronizer, @@ -102,7 +106,12 @@ export class AztecNodeService implements AztecNode { } const log = createDebugLogger('aztec:node'); - const store = await AztecLmdbStore.open(config.l1Contracts.rollupAddress, config.dataDirectory); + const storeLog = createDebugLogger('aztec:node:lmdb'); + const store = await initStoreForRollup( + AztecLmdbStore.open(config.dataDirectory, storeLog), + config.l1Contracts.rollupAddress, + storeLog, + ); let archiver: ArchiveSource; if (!config.archiverUrl) { @@ -237,6 +246,14 @@ export class AztecNodeService implements AztecNode { return await this.contractDataSource.getContractData(contractAddress); } + public getContractClass(id: Fr): Promise { + return this.contractDataSource.getContractClass(id); + } + + public getContract(address: AztecAddress): Promise { + return this.contractDataSource.getContract(address); + } + /** * Gets up to `limit` amount of logs starting from `from`. * @param from - Number of the L2 block to which corresponds the first logs to be returned. @@ -545,7 +562,16 @@ export class AztecNodeService implements AztecNode { public async simulatePublicCalls(tx: Tx) { this.log.info(`Simulating tx ${await tx.getTxHash()}`); const blockNumber = (await this.blockSource.getBlockNumber()) + 1; - const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables(new Fr(blockNumber)); + + // If sequencer is not initialized, we just set these values to zero for simulation. + const coinbase = this.sequencer?.coinbase || EthAddress.ZERO; + const feeRecipient = this.sequencer?.feeRecipient || AztecAddress.ZERO; + + const newGlobalVariables = await this.globalVariableBuilder.buildGlobalVariables( + new Fr(blockNumber), + coinbase, + feeRecipient, + ); const prevHeader = (await this.blockSource.getBlock(-1))?.header; // Instantiate merkle trees so uncommitted updates by this simulation are local to it. diff --git a/yarn-project/aztec-nr/.gitrepo b/yarn-project/aztec-nr/.gitrepo index a3b9039f7f9..d26013694dc 100644 --- a/yarn-project/aztec-nr/.gitrepo +++ b/yarn-project/aztec-nr/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/aztec-nr branch = master - commit = c3b90d79a82de709fd77849f59d4f7dd5096dd30 + commit = ca7c38c9a64f6d2efd1f12016bcb1071a0b00c0b method = merge cmdver = 0.4.6 - parent = 993f715472eaedc2d93a8e3893625e52d790626e + parent = 8d6400203e7df4aa5ca47256cc7a6971d7d9d3ee diff --git a/yarn-project/aztec-nr/authwit/src/entrypoint.nr b/yarn-project/aztec-nr/authwit/src/entrypoint.nr index 98987d49e36..13407a40ecc 100644 --- a/yarn-project/aztec-nr/authwit/src/entrypoint.nr +++ b/yarn-project/aztec-nr/authwit/src/entrypoint.nr @@ -1,13 +1,6 @@ -use dep::aztec::abi; use dep::aztec::context::PrivateContext; use dep::aztec::protocol_types::{ - abis::{ - call_stack_item::{ - PrivateCallStackItem, - PublicCallStackItem, - }, - function_selector::FunctionSelector, - }, + abis::function_selector::FunctionSelector, address::AztecAddress, constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, diff --git a/yarn-project/aztec-nr/aztec/src/abi.nr b/yarn-project/aztec-nr/aztec/src/abi.nr deleted file mode 100644 index 6e194584313..00000000000 --- a/yarn-project/aztec-nr/aztec/src/abi.nr +++ /dev/null @@ -1,85 +0,0 @@ -use dep::protocol_types::{ - abis::{ - call_context::CallContext, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_circuit_public_inputs::PublicCircuitPublicInputs, - }, - contrakt::deployment_data::ContractDeploymentData, - hash::hash_args, - traits::{Hash, Serialize}, - header::Header, -}; - -// docs:start:private-global-variables -struct PrivateGlobalVariables { - chain_id: Field, - version: Field, -} -// docs:end:private-global-variables - -impl Serialize<2> for PrivateGlobalVariables { - fn serialize(self) -> [Field; 2] { - [self.chain_id, self.version] - } -} - -// docs:start:public-global-variables -struct PublicGlobalVariables { - chain_id: Field, - version: Field, - block_number: Field, - timestamp: Field, -} -// docs:end:public-global-variables - -impl Serialize<4> for PublicGlobalVariables { - fn serialize(self) -> [Field; 4] { - [self.chain_id, self.version, self.block_number, self.timestamp] - } -} - -// PrivateContextInputs are expected to be provided to each private function -// docs:start:private-context-inputs -struct PrivateContextInputs { - call_context : CallContext, - historical_header: Header, - contract_deployment_data: ContractDeploymentData, - private_global_variables: PrivateGlobalVariables, -} -// docs:end:private-context-inputs - -// PublicContextInputs are expected to be provided to each public function -// docs:start:public-context-inputs -struct PublicContextInputs { - call_context: CallContext, - historical_header: Header, - - public_global_variables: PublicGlobalVariables, -} -// docs:end:public-context-inputs - -struct Hasher { - fields: [Field], -} - -impl Hash for Hasher { - fn hash(self) -> Field { - hash_args(self.fields) - } -} - -impl Hasher { - pub fn new()-> Self { - Self { fields: [] } - } - - pub fn add(&mut self, field: Field) { - self.fields = self.fields.push_back(field); - } - - pub fn add_multiple(&mut self, fields: [Field; N]) { - for i in 0..N { - self.fields = self.fields.push_back(fields[i]); - } - } -} diff --git a/yarn-project/aztec-nr/aztec/src/avm.nr b/yarn-project/aztec-nr/aztec/src/avm.nr new file mode 100644 index 00000000000..3d9885db80d --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/avm.nr @@ -0,0 +1 @@ +mod context; diff --git a/yarn-project/aztec-nr/aztec/src/avm/context.nr b/yarn-project/aztec-nr/aztec/src/avm/context.nr new file mode 100644 index 00000000000..4e6d3f56f21 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/avm/context.nr @@ -0,0 +1,50 @@ +use dep::protocol_types::address::{ + AztecAddress, + EthAddress, +}; + +// Getters that will be converted by the transpiler into their +// own opcodes +struct AvmContext {} + +// No new function as this struct is entirely static getters +impl AvmContext { + #[oracle(address)] + pub fn address() -> AztecAddress {} + + #[oracle(storageAddress)] + pub fn storage_address() -> AztecAddress {} + + #[oracle(origin)] + pub fn origin() -> AztecAddress {} + + #[oracle(sender)] + pub fn sender() -> AztecAddress {} + + #[oracle(portal)] + pub fn portal() -> EthAddress {} + + #[oracle(feePerL1Gas)] + pub fn fee_per_l1_gas() -> Field {} + + #[oracle(feePerL2Gas)] + pub fn fee_per_l2_gas() -> Field {} + + #[oracle(feePerDaGas)] + pub fn fee_per_da_gas() -> Field {} + + #[oracle(chainId)] + pub fn chain_id() -> Field {} + + #[oracle(version)] + pub fn version() -> Field {} + + #[oracle(blockNumber)] + pub fn block_number() -> Field {} + + #[oracle(timestamp)] + pub fn timestamp() -> Field {} + + // #[oracle(contractCallDepth)] + // pub fn contract_call_depth() -> Field {} +} diff --git a/yarn-project/aztec-nr/aztec/src/context.nr b/yarn-project/aztec-nr/aztec/src/context.nr index 3eda05bb01e..8cc2c2a22c2 100644 --- a/yarn-project/aztec-nr/aztec/src/context.nr +++ b/yarn-project/aztec-nr/aztec/src/context.nr @@ -1,617 +1,13 @@ -use crate::{ - abi::{ - PrivateContextInputs, - PublicContextInputs, - }, - key::nullifier_key::validate_nullifier_key_against_address, - messaging::process_l1_to_l2_message, - oracle::{ - arguments, - call_private_function::call_private_function_internal, - public_call::call_public_function_internal, - enqueue_public_function_call::enqueue_public_function_call_internal, - context::get_portal_address, - header::get_header_at, - nullifier_key::{get_nullifier_key_pair, NullifierKeyPair}, - }, - utils::Reader, -}; -use dep::protocol_types::{ - abis::{ - append_only_tree_snapshot::AppendOnlyTreeSnapshot, - call_context::CallContext, - global_variables::GlobalVariables, - function_data::FunctionData, - function_selector::FunctionSelector, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_circuit_public_inputs::PublicCircuitPublicInputs, - call_stack_item::PrivateCallStackItem, - call_stack_item::PublicCallStackItem, - side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - address::{ - AztecAddress, - EthAddress, - }, - constants::{ - MAX_NEW_COMMITMENTS_PER_CALL, - MAX_NEW_L2_TO_L1_MSGS_PER_CALL, - MAX_NEW_NULLIFIERS_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH, - }, - contract_class::ContractClassId, - contrakt::{ - deployment_data::ContractDeploymentData, - storage_read::StorageRead, - storage_update_request::StorageUpdateRequest, - }, - grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey, - hash::hash_args, - header::Header, - state_reference::StateReference, -}; -use dep::std::{ - option::Option, -}; +mod globals; +mod inputs; -// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) -// use dep::std::collections::vec::Vec; +mod private_context; +mod public_context; +mod avm; -// When finished, one can call .finish() to convert back to the abi -struct PrivateContext { - // docs:start:private-context - inputs: PrivateContextInputs, - side_effect_counter: u32, - - args_hash : Field, - return_values : BoundedVec, - - read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, - - new_commitments: BoundedVec, - new_nullifiers: BoundedVec, - - private_call_stack_hashes : BoundedVec, - public_call_stack_hashes : BoundedVec, - new_l2_to_l1_msgs : BoundedVec, - // docs:end:private-context - - // Header of a block whose state is used during private execution (not the block the transaction is included in). - historical_header: Header, - - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - // encrypted_logs_preimages: Vec, - // unencrypted_logs_preimages: Vec, - - nullifier_key: Option, -} - -impl PrivateContext { - pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext { - PrivateContext { - inputs: inputs, - side_effect_counter: inputs.call_context.start_side_effect_counter, - - args_hash: args_hash, - return_values: BoundedVec::new(0), - - read_requests: BoundedVec::new(SideEffect::empty()), - nullifier_key_validation_requests: BoundedVec::new(NullifierKeyValidationRequest::empty()), - - new_commitments: BoundedVec::new(SideEffect::empty()), - new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), - - historical_header: inputs.historical_header, - - private_call_stack_hashes: BoundedVec::new(0), - public_call_stack_hashes: BoundedVec::new(0), - new_l2_to_l1_msgs: BoundedVec::new(0), - - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - // encrypted_logs_preimages: Vec::new(), - // unencrypted_logs_preimages: Vec::new(), - - nullifier_key: Option::none(), - } - } - - pub fn msg_sender(self) -> AztecAddress { - self.inputs.call_context.msg_sender - } - - pub fn this_address(self) -> AztecAddress { - self.inputs.call_context.storage_contract_address - } - - pub fn this_portal_address(self) -> EthAddress { - self.inputs.call_context.portal_contract_address - } - - pub fn chain_id(self) -> Field { - self.inputs.private_global_variables.chain_id - } - - pub fn version(self) -> Field { - self.inputs.private_global_variables.version - } - - pub fn selector(self) -> FunctionSelector { - self.inputs.call_context.function_selector - } - - // Returns the header of a block whose state is used during private execution (not the block the transaction is - // included in). - pub fn get_header(self) -> Header { - self.historical_header - } - - // Returns the header of an arbitrary block whose block number is less than or equal to the block number - // of historical header. - pub fn get_header_at(self, block_number: u32) -> Header { - get_header_at(block_number, self) - } - - pub fn finish(self) -> PrivateCircuitPublicInputs { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let encrypted_log_preimages_length = 0; - let unencrypted_log_preimages_length = 0; - - let priv_circuit_pub_inputs = PrivateCircuitPublicInputs { - call_context: self.inputs.call_context, - args_hash: self.args_hash, - return_values: self.return_values.storage, - read_requests: self.read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, - new_commitments: self.new_commitments.storage, - new_nullifiers: self.new_nullifiers.storage, - private_call_stack_hashes: self.private_call_stack_hashes.storage, - public_call_stack_hashes: self.public_call_stack_hashes.storage, - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - end_side_effect_counter: self.side_effect_counter, - encrypted_logs_hash: encrypted_logs_hash, - unencrypted_logs_hash: unencrypted_logs_hash, - encrypted_log_preimages_length: encrypted_log_preimages_length, - unencrypted_log_preimages_length: unencrypted_log_preimages_length, - historical_header: self.historical_header, - contract_deployment_data: self.inputs.contract_deployment_data, - chain_id: self.inputs.private_global_variables.chain_id, - version: self.inputs.private_global_variables.version, - }; - priv_circuit_pub_inputs - } - - pub fn push_read_request(&mut self, read_request: Field) { - let side_effect = SideEffect { - value: read_request, - counter: self.side_effect_counter, - }; - self.read_requests.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; - } - - pub fn push_new_note_hash(&mut self, note_hash: Field) { - let side_effect = SideEffect { - value: note_hash, - counter: self.side_effect_counter, - }; - self.new_commitments.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; - } - - pub fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field) { - let side_effect = SideEffectLinkedToNoteHash { - value: nullifier, - note_hash: nullified_commitment, - counter: self.side_effect_counter, - }; - self.new_nullifiers.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; - } - - pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey { - let key_pair = if self.nullifier_key.is_none() { - let key_pair = get_nullifier_key_pair(account); - validate_nullifier_key_against_address(account, key_pair.public_key); - let request = NullifierKeyValidationRequest { public_key: key_pair.public_key, secret_key: key_pair.secret_key }; - self.nullifier_key_validation_requests.push(request); - self.nullifier_key = Option::some(key_pair); - key_pair - } else { - let key_pair = self.nullifier_key.unwrap_unchecked(); - // If MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is larger than 1, need to update the way the key pair is cached. - assert(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL == 1); - assert(key_pair.account == account, "Cannot query nullifier key for more than one account per call"); - key_pair - }; - key_pair.secret_key - } - - // docs:start:context_message_portal - pub fn message_portal(&mut self, content: Field) - // docs:end:context_message_portal - { - self.new_l2_to_l1_msgs.push(content); - } - - // PrivateContextInputs must be temporarily passed in to prevent too many unknowns - // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned - // docs:start:context_consume_l1_to_l2_message - // docs:start:consume_l1_to_l2_message - pub fn consume_l1_to_l2_message( - &mut self, - msg_key: Field, - content: Field, - secret: Field - ) - // docs:end:context_consume_l1_to_l2_message - { - let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, self.this_address(), self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); - - // Push nullifier (and the "commitment" corresponding to this can be "empty") - self.push_new_nullifier(nullifier, 0) - } - // docs:end:consume_l1_to_l2_message - - pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { - let _void1 = self.inputs; - let _void2 = log; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - } - - pub fn accumulate_unencrypted_logs(&mut self, log: T) { - let _void1 = self.inputs; - let _void2 = log; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - } - - pub fn call_private_function( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args: [Field; ARGS_COUNT] - ) -> [Field; RETURN_VALUES_LENGTH] { - let args_hash = hash_args(args); - assert(args_hash == arguments::pack_arguments(args)); - self.call_private_function_with_packed_args(contract_address, function_selector, args_hash) - } - - pub fn call_private_function_no_args( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - ) -> [Field; RETURN_VALUES_LENGTH] { - self.call_private_function_with_packed_args(contract_address, function_selector, 0) - } - - pub fn call_private_function_with_packed_args( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args_hash: Field - ) -> [Field; RETURN_VALUES_LENGTH] { - let fields = call_private_function_internal( - contract_address, - function_selector, - args_hash, - self.side_effect_counter, - ); - let mut reader = Reader::new(fields); - - let item = PrivateCallStackItem { - contract_address: AztecAddress::from_field(reader.read()), - function_data: reader.read_struct(FunctionData::deserialize), - public_inputs: reader.read_struct(PrivateCircuitPublicInputs::deserialize), - is_execution_request: reader.read() as bool, - }; - - reader.finish(); - - assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter); - self.side_effect_counter = item.public_inputs.end_side_effect_counter + 1; - - assert(contract_address.eq(item.contract_address)); - assert(function_selector.eq(item.function_data.selector)); - - assert(args_hash == item.public_inputs.args_hash); - - assert(item.is_execution_request == false); - - // Assert that the call context of the enqueued call generated by the oracle matches our request. - // We are issuing a regular call which is not delegate, static, or deployment. We also constrain - // the msg_sender in the nested call to be equal to our address, and the execution context address - // for the nested call to be equal to the address we actually called. - assert(item.public_inputs.call_context.is_delegate_call == false); - assert(item.public_inputs.call_context.is_static_call == false); - assert(item.public_inputs.call_context.is_contract_deployment == false); - assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); - assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); - - self.private_call_stack_hashes.push(item.hash()); - - item.public_inputs.return_values - } - - pub fn call_public_function( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args: [Field; ARGS_COUNT] - ) { - let args_hash = hash_args(args); - assert(args_hash == arguments::pack_arguments(args)); - self.call_public_function_with_packed_args(contract_address, function_selector, args_hash) - } - - pub fn call_public_function_no_args( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - ) { - self.call_public_function_with_packed_args(contract_address, function_selector, 0) - } - - pub fn call_public_function_with_packed_args( - &mut self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args_hash: Field - ) { - let fields = enqueue_public_function_call_internal( - contract_address, - function_selector, - args_hash, - self.side_effect_counter - ); - - let mut reader = Reader::new(fields); - - // Note: Not using PublicCirclePublicInputs::deserialize here, because everything below args_hash is 0 and - // there is no more data in fields because there is only ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE fields! - let item = PublicCallStackItem { - contract_address: AztecAddress::from_field(reader.read()), - function_data: reader.read_struct(FunctionData::deserialize), - public_inputs: PublicCircuitPublicInputs { - call_context: reader.read_struct(CallContext::deserialize), - args_hash: reader.read(), - return_values: [0; RETURN_VALUES_LENGTH], - contract_storage_update_requests: [StorageUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL], - contract_storage_reads: [StorageRead::empty(); MAX_PUBLIC_DATA_READS_PER_CALL], - public_call_stack_hashes: [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], - new_commitments: [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL], - new_nullifiers: [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL], - new_l2_to_l1_msgs:[0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], - unencrypted_logs_hash:[0; NUM_FIELDS_PER_SHA256], - unencrypted_log_preimages_length: 0, - historical_header: Header::empty(), - prover_address: AztecAddress::zero(), - }, - is_execution_request: true, - }; - reader.finish(); - - assert(contract_address.eq(item.contract_address)); - assert(function_selector.eq(item.function_data.selector)); - - assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter); - // We increment the sideffect counter by one, to account for the call itself being a side effect. - self.side_effect_counter = self.side_effect_counter + 1; - - assert(args_hash == item.public_inputs.args_hash); - - // Assert that the call context of the enqueued call generated by the oracle matches our request. - // We are issuing a regular call which is not delegate, static, or deployment. We also constrain - // the msg_sender in the nested call to be equal to our address, and the execution context address - // for the nested call to be equal to the address we actually called. - assert(item.public_inputs.call_context.is_delegate_call == false); - assert(item.public_inputs.call_context.is_static_call == false); - assert(item.public_inputs.call_context.is_contract_deployment == false); - assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); - assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); - - self.public_call_stack_hashes.push(item.hash()); - } -} - -struct PublicContext { - inputs: PublicContextInputs, - side_effect_counter: u32, - - args_hash : Field, - return_values : BoundedVec, - - contract_storage_update_requests: BoundedVec, - contract_storage_reads: BoundedVec, - public_call_stack_hashes: BoundedVec, - - new_commitments: BoundedVec, - new_nullifiers: BoundedVec, - - new_l2_to_l1_msgs: BoundedVec, - - unencrypted_logs_hash: BoundedVec, - unencrypted_logs_preimages_length: Field, - - // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block - // previous to the one in which the tx is included. - historical_header: Header, - prover_address: AztecAddress, -} - -impl PublicContext { - pub fn new(inputs: PublicContextInputs, args_hash: Field) -> PublicContext { - let empty_storage_read = StorageRead::empty(); - let empty_storage_update = StorageUpdateRequest::empty(); - PublicContext { - inputs: inputs, - side_effect_counter: inputs.call_context.start_side_effect_counter, - - args_hash: args_hash, - return_values: BoundedVec::new(0), - - contract_storage_update_requests: BoundedVec::new(empty_storage_update), - contract_storage_reads: BoundedVec::new(empty_storage_read), - public_call_stack_hashes: BoundedVec::new(0), - - new_commitments: BoundedVec::new(SideEffect::empty()), - new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), - - new_l2_to_l1_msgs: BoundedVec::new(0), - - - unencrypted_logs_hash: BoundedVec::new(0), - unencrypted_logs_preimages_length: 0, - - historical_header: inputs.historical_header, - prover_address: AztecAddress::zero(), - - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - // encrypted_logs_preimages: Vec::new(), - // unencrypted_logs_preimages: Vec::new(), - } - } - - pub fn msg_sender(self) -> AztecAddress { - self.inputs.call_context.msg_sender - } - - pub fn this_address(self) -> AztecAddress { - self.inputs.call_context.storage_contract_address - } - - pub fn this_portal_address(self) -> EthAddress { - self.inputs.call_context.portal_contract_address - } - - pub fn chain_id(self) -> Field { - self.inputs.public_global_variables.chain_id - } - - pub fn version(self) -> Field { - self.inputs.public_global_variables.version - } - - pub fn selector(self) -> FunctionSelector { - self.inputs.call_context.function_selector - } - - pub fn block_number(self) -> Field { - self.inputs.public_global_variables.block_number - } - - pub fn timestamp(self) -> Field { - self.inputs.public_global_variables.timestamp - } - - pub fn finish(self) -> PublicCircuitPublicInputs { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let unencrypted_log_preimages_length = 0; - - - // Compute the public call stack hashes - let pub_circuit_pub_inputs = PublicCircuitPublicInputs { - call_context: self.inputs.call_context, // Done - args_hash: self.args_hash, // Done - contract_storage_update_requests: self.contract_storage_update_requests.storage, - contract_storage_reads: self.contract_storage_reads.storage, - return_values: self.return_values.storage, - new_commitments: self.new_commitments.storage, - new_nullifiers: self.new_nullifiers.storage, - public_call_stack_hashes: self.public_call_stack_hashes.storage, - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - unencrypted_logs_hash: unencrypted_logs_hash, - unencrypted_log_preimages_length: unencrypted_log_preimages_length, - historical_header: self.inputs.historical_header, - prover_address: self.prover_address, - }; - pub_circuit_pub_inputs - } - - pub fn push_new_note_hash(&mut self, note_hash: Field) { - let side_effect = SideEffect { - value: note_hash, - counter: self.side_effect_counter - }; - self.new_commitments.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; - } - - pub fn push_new_nullifier(&mut self, nullifier: Field, _nullified_commitment: Field) { - let side_effect = SideEffectLinkedToNoteHash { - value: nullifier, - note_hash: 0, // cannot nullify pending notes in public context - counter: self.side_effect_counter - }; - self.new_nullifiers.push(side_effect); - self.side_effect_counter = self.side_effect_counter + 1; - } - - pub fn message_portal(&mut self, content: Field) { - self.new_l2_to_l1_msgs.push(content); - } - - // PrivateContextInputs must be temporarily passed in to prevent too many unknowns - // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned - pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field) { - let this = (*self).this_address(); - let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, this, self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); - - // Push nullifier (and the "commitment" corresponding to this can be "empty") - self.push_new_nullifier(nullifier, 0) - } - - pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { - let _void1 = self; - let _void2 = log; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - } - - pub fn accumulate_unencrypted_logs(&mut self, log: T) { - let _void1 = self; - let _void2 = log; - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - } - - pub fn call_public_function( - _self: Self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args: [Field; ARGS_COUNT], - ) -> [Field; RETURN_VALUES_LENGTH] { - let args_hash = hash_args(args); - assert(args_hash == arguments::pack_arguments(args)); - call_public_function_internal( - contract_address, - function_selector, - args_hash, - ) - } - - pub fn call_public_function_no_args( - _self: Self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - ) -> [Field; RETURN_VALUES_LENGTH] { - call_public_function_internal( - contract_address, - function_selector, - 0, - ) - } - -} +use private_context::PrivateContext; +use public_context::PublicContext; +use avm::AVMContext; struct Context { private: Option<&mut PrivateContext>, diff --git a/yarn-project/aztec-nr/aztec/src/context/avm.nr b/yarn-project/aztec-nr/aztec/src/context/avm.nr new file mode 100644 index 00000000000..98c578e59db --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/avm.nr @@ -0,0 +1,54 @@ +use dep::protocol_types::address::{ + AztecAddress, + EthAddress, +}; + +// Getters that will be converted by the transpiler into their +// own opcodes +struct AVMContext {} + +impl AVMContext { + // Empty new function enables retaining context. syntax + pub fn new() -> Self { + Self {} + } + + #[oracle(address)] + pub fn address(self) -> AztecAddress {} + + #[oracle(storageAddress)] + pub fn storage_address(self) -> AztecAddress {} + + #[oracle(origin)] + pub fn origin(self) -> AztecAddress {} + + #[oracle(sender)] + pub fn sender(self) -> AztecAddress {} + + #[oracle(portal)] + pub fn portal(self) -> EthAddress {} + + #[oracle(feePerL1Gas)] + pub fn fee_per_l1_gas(self) -> Field {} + + #[oracle(feePerL2Gas)] + pub fn fee_per_l2_gas(self) -> Field {} + + #[oracle(feePerDaGas)] + pub fn fee_per_da_gas(self) -> Field {} + + #[oracle(chainId)] + pub fn chain_id(self) -> Field {} + + #[oracle(version)] + pub fn version(self) -> Field {} + + #[oracle(blockNumber)] + pub fn block_number(self) -> Field {} + + #[oracle(timestamp)] + pub fn timestamp(self) -> Field {} + + // #[oracle(contractCallDepth)] + // pub fn contract_call_depth(self) -> Field {} +} diff --git a/yarn-project/aztec-nr/aztec/src/context/globals.nr b/yarn-project/aztec-nr/aztec/src/context/globals.nr new file mode 100644 index 00000000000..8b50aa87a59 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/globals.nr @@ -0,0 +1,2 @@ +mod private_global_variables; +mod public_global_variables; diff --git a/yarn-project/aztec-nr/aztec/src/context/globals/private_global_variables.nr b/yarn-project/aztec-nr/aztec/src/context/globals/private_global_variables.nr new file mode 100644 index 00000000000..012db96d33c --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/globals/private_global_variables.nr @@ -0,0 +1,16 @@ +use dep::protocol_types::traits::Serialize; + +global PRIVATE_GLOBAL_VARIABLES_LENGTH: Field = 2; + +// docs:start:private-global-variables +struct PrivateGlobalVariables { + chain_id: Field, + version: Field, +} +// docs:end:private-global-variables + +impl Serialize for PrivateGlobalVariables { + fn serialize(self) -> [Field; PRIVATE_GLOBAL_VARIABLES_LENGTH] { + [self.chain_id, self.version] + } +} diff --git a/yarn-project/aztec-nr/aztec/src/context/globals/public_global_variables.nr b/yarn-project/aztec-nr/aztec/src/context/globals/public_global_variables.nr new file mode 100644 index 00000000000..de68887afa8 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/globals/public_global_variables.nr @@ -0,0 +1,2 @@ +// protocl global vars are equal to the private ones so we just re-export them here under a different name +use dep::protocol_types::abis::global_variables::GlobalVariables as PublicGlobalVariables; diff --git a/yarn-project/aztec-nr/aztec/src/context/inputs.nr b/yarn-project/aztec-nr/aztec/src/context/inputs.nr new file mode 100644 index 00000000000..0d7c56574d5 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/inputs.nr @@ -0,0 +1,5 @@ +mod private_context_inputs; +mod public_context_inputs; + +use crate::context::inputs::private_context_inputs::PrivateContextInputs; +use crate::context::inputs::public_context_inputs::PublicContextInputs; diff --git a/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr b/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr new file mode 100644 index 00000000000..b96f62e6e50 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/inputs/private_context_inputs.nr @@ -0,0 +1,16 @@ +use dep::protocol_types::{ + abis::call_context::CallContext, + contrakt::deployment_data::ContractDeploymentData, + header::Header, +}; +use crate::context::globals::private_global_variables::PrivateGlobalVariables; + +// PrivateContextInputs are expected to be provided to each private function +// docs:start:private-context-inputs +struct PrivateContextInputs { + call_context : CallContext, + historical_header: Header, + contract_deployment_data: ContractDeploymentData, + private_global_variables: PrivateGlobalVariables, +} +// docs:end:private-context-inputs \ No newline at end of file diff --git a/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr b/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr new file mode 100644 index 00000000000..6fefcfed3b7 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/inputs/public_context_inputs.nr @@ -0,0 +1,16 @@ +use crate::context::globals::public_global_variables::PublicGlobalVariables; + +use dep::protocol_types::{ + abis::call_context::CallContext, + header::Header, +}; + +// PublicContextInputs are expected to be provided to each public function +// docs:start:public-context-inputs +struct PublicContextInputs { + call_context: CallContext, + historical_header: Header, + + public_global_variables: PublicGlobalVariables, +} +// docs:end:public-context-inputs diff --git a/yarn-project/aztec-nr/aztec/src/context/private_context.nr b/yarn-project/aztec-nr/aztec/src/context/private_context.nr new file mode 100644 index 00000000000..1fdad5a141a --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/private_context.nr @@ -0,0 +1,405 @@ +use crate::{ + context::inputs::PrivateContextInputs, + key::nullifier_key::validate_nullifier_key_against_address, + messaging::process_l1_to_l2_message, + oracle::{ + arguments, + call_private_function::call_private_function_internal, + enqueue_public_function_call::enqueue_public_function_call_internal, + context::get_portal_address, + header::get_header_at, + nullifier_key::{get_nullifier_key_pair, NullifierKeyPair}, + }, +}; +use dep::protocol_types::{ + abis::{ + call_context::CallContext, + function_data::FunctionData, + function_selector::FunctionSelector, + nullifier_key_validation_request::NullifierKeyValidationRequest, + private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + }, + address::{ + AztecAddress, + EthAddress, + }, + constants::{ + MAX_NEW_COMMITMENTS_PER_CALL, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, + MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH, + }, + contrakt::{ + storage_read::StorageRead, + storage_update_request::StorageUpdateRequest, + }, + grumpkin_private_key::GrumpkinPrivateKey, + hash::hash_args, + header::Header, + utils::reader::Reader, +}; +use dep::std::option::Option; + +// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) +// use dep::std::collections::vec::Vec; + +// When finished, one can call .finish() to convert back to the abi +struct PrivateContext { + // docs:start:private-context + inputs: PrivateContextInputs, + side_effect_counter: u32, + + meta_hwm: u32, + + args_hash : Field, + return_values : BoundedVec, + + read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, + + new_commitments: BoundedVec, + new_nullifiers: BoundedVec, + + private_call_stack_hashes : BoundedVec, + public_call_stack_hashes : BoundedVec, + new_l2_to_l1_msgs : BoundedVec, + // docs:end:private-context + + // Header of a block whose state is used during private execution (not the block the transaction is included in). + historical_header: Header, + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + // encrypted_logs_preimages: Vec, + // unencrypted_logs_preimages: Vec, + + nullifier_key: Option, +} + +impl PrivateContext { + pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext { + PrivateContext { + inputs: inputs, + side_effect_counter: inputs.call_context.start_side_effect_counter, + meta_hwm: 0, + + args_hash: args_hash, + return_values: BoundedVec::new(0), + + read_requests: BoundedVec::new(SideEffect::empty()), + nullifier_key_validation_requests: BoundedVec::new(NullifierKeyValidationRequest::empty()), + + new_commitments: BoundedVec::new(SideEffect::empty()), + new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), + + historical_header: inputs.historical_header, + + private_call_stack_hashes: BoundedVec::new(0), + public_call_stack_hashes: BoundedVec::new(0), + new_l2_to_l1_msgs: BoundedVec::new(0), + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + // encrypted_logs_preimages: Vec::new(), + // unencrypted_logs_preimages: Vec::new(), + + nullifier_key: Option::none(), + } + } + + pub fn msg_sender(self) -> AztecAddress { + self.inputs.call_context.msg_sender + } + + pub fn this_address(self) -> AztecAddress { + self.inputs.call_context.storage_contract_address + } + + pub fn this_portal_address(self) -> EthAddress { + self.inputs.call_context.portal_contract_address + } + + pub fn chain_id(self) -> Field { + self.inputs.private_global_variables.chain_id + } + + pub fn version(self) -> Field { + self.inputs.private_global_variables.version + } + + pub fn selector(self) -> FunctionSelector { + self.inputs.call_context.function_selector + } + + // Returns the header of a block whose state is used during private execution (not the block the transaction is + // included in). + pub fn get_header(self) -> Header { + self.historical_header + } + + // Returns the header of an arbitrary block whose block number is less than or equal to the block number + // of historical header. + pub fn get_header_at(self, block_number: u32) -> Header { + get_header_at(block_number, self) + } + + pub fn finish(self) -> PrivateCircuitPublicInputs { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let encrypted_log_preimages_length = 0; + let unencrypted_log_preimages_length = 0; + + let priv_circuit_pub_inputs = PrivateCircuitPublicInputs { + call_context: self.inputs.call_context, + args_hash: self.args_hash, + return_values: self.return_values.storage, + meta_hwm: self.meta_hwm, + read_requests: self.read_requests.storage, + nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, + new_commitments: self.new_commitments.storage, + new_nullifiers: self.new_nullifiers.storage, + private_call_stack_hashes: self.private_call_stack_hashes.storage, + public_call_stack_hashes: self.public_call_stack_hashes.storage, + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + end_side_effect_counter: self.side_effect_counter, + encrypted_logs_hash: encrypted_logs_hash, + unencrypted_logs_hash: unencrypted_logs_hash, + encrypted_log_preimages_length: encrypted_log_preimages_length, + unencrypted_log_preimages_length: unencrypted_log_preimages_length, + historical_header: self.historical_header, + contract_deployment_data: self.inputs.contract_deployment_data, + chain_id: self.inputs.private_global_variables.chain_id, + version: self.inputs.private_global_variables.version, + }; + priv_circuit_pub_inputs + } + + pub fn push_read_request(&mut self, read_request: Field) { + let side_effect = SideEffect { + value: read_request, + counter: self.side_effect_counter, + }; + self.read_requests.push(side_effect); + self.side_effect_counter = self.side_effect_counter + 1; + } + + pub fn push_new_note_hash(&mut self, note_hash: Field) { + let side_effect = SideEffect { + value: note_hash, + counter: self.side_effect_counter, + }; + self.new_commitments.push(side_effect); + self.side_effect_counter = self.side_effect_counter + 1; + } + + pub fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field) { + let side_effect = SideEffectLinkedToNoteHash { + value: nullifier, + note_hash: nullified_commitment, + counter: self.side_effect_counter, + }; + self.new_nullifiers.push(side_effect); + self.side_effect_counter = self.side_effect_counter + 1; + } + + pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey { + let key_pair = if self.nullifier_key.is_none() { + let key_pair = get_nullifier_key_pair(account); + validate_nullifier_key_against_address(account, key_pair.public_key); + let request = NullifierKeyValidationRequest { public_key: key_pair.public_key, secret_key: key_pair.secret_key }; + self.nullifier_key_validation_requests.push(request); + self.nullifier_key = Option::some(key_pair); + key_pair + } else { + let key_pair = self.nullifier_key.unwrap_unchecked(); + // If MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is larger than 1, need to update the way the key pair is cached. + assert(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL == 1); + assert(key_pair.account == account, "Cannot query nullifier key for more than one account per call"); + key_pair + }; + key_pair.secret_key + } + + // docs:start:context_message_portal + pub fn message_portal(&mut self, content: Field) + // docs:end:context_message_portal + { + self.new_l2_to_l1_msgs.push(content); + } + + // PrivateContextInputs must be temporarily passed in to prevent too many unknowns + // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned + // docs:start:context_consume_l1_to_l2_message + // docs:start:consume_l1_to_l2_message + pub fn consume_l1_to_l2_message( + &mut self, + msg_key: Field, + content: Field, + secret: Field + ) + // docs:end:context_consume_l1_to_l2_message + { + let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, self.this_address(), self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); + + // Push nullifier (and the "commitment" corresponding to this can be "empty") + self.push_new_nullifier(nullifier, 0) + } + // docs:end:consume_l1_to_l2_message + + pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { + let _void1 = self.inputs; + let _void2 = log; + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + } + + pub fn accumulate_unencrypted_logs(&mut self, log: T) { + let _void1 = self.inputs; + let _void2 = log; + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + } + + pub fn call_private_function( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH] { + let args_hash = hash_args(args); + assert(args_hash == arguments::pack_arguments(args)); + self.call_private_function_with_packed_args(contract_address, function_selector, args_hash) + } + + pub fn call_private_function_no_args( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + ) -> [Field; RETURN_VALUES_LENGTH] { + self.call_private_function_with_packed_args(contract_address, function_selector, 0) + } + + pub fn call_private_function_with_packed_args( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args_hash: Field + ) -> [Field; RETURN_VALUES_LENGTH] { + let item = call_private_function_internal( + contract_address, + function_selector, + args_hash, + self.side_effect_counter, + ); + + assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter); + self.side_effect_counter = item.public_inputs.end_side_effect_counter + 1; + + assert(contract_address.eq(item.contract_address)); + assert(function_selector.eq(item.function_data.selector)); + + assert(args_hash == item.public_inputs.args_hash); + + // Assert that the call context of the enqueued call generated by the oracle matches our request. + // We are issuing a regular call which is not delegate, static, or deployment. We also constrain + // the msg_sender in the nested call to be equal to our address, and the execution context address + // for the nested call to be equal to the address we actually called. + assert(item.public_inputs.call_context.is_delegate_call == false); + assert(item.public_inputs.call_context.is_static_call == false); + assert(item.public_inputs.call_context.is_contract_deployment == false); + assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); + assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); + + self.private_call_stack_hashes.push(item.hash()); + + item.public_inputs.return_values + } + + pub fn call_public_function( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) { + let args_hash = hash_args(args); + assert(args_hash == arguments::pack_arguments(args)); + self.call_public_function_with_packed_args(contract_address, function_selector, args_hash) + } + + pub fn call_public_function_no_args( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + ) { + self.call_public_function_with_packed_args(contract_address, function_selector, 0) + } + + pub fn call_public_function_with_packed_args( + &mut self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args_hash: Field + ) { + let fields = enqueue_public_function_call_internal( + contract_address, + function_selector, + args_hash, + self.side_effect_counter + ); + + let mut reader = Reader::new(fields); + + // Note: Not using PublicCirclePublicInputs::deserialize here, because everything below args_hash is 0 and + // there is no more data in fields because there is only ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE fields! + let item = PublicCallStackItem { + contract_address: AztecAddress::from_field(reader.read()), + function_data: reader.read_struct(FunctionData::deserialize), + public_inputs: PublicCircuitPublicInputs { + call_context: reader.read_struct(CallContext::deserialize), + args_hash: reader.read(), + return_values: [0; RETURN_VALUES_LENGTH], + contract_storage_update_requests: [StorageUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL], + contract_storage_reads: [StorageRead::empty(); MAX_PUBLIC_DATA_READS_PER_CALL], + public_call_stack_hashes: [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL], + new_commitments: [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL], + new_nullifiers: [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL], + new_l2_to_l1_msgs:[0; MAX_NEW_L2_TO_L1_MSGS_PER_CALL], + unencrypted_logs_hash:[0; NUM_FIELDS_PER_SHA256], + unencrypted_log_preimages_length: 0, + historical_header: Header::empty(), + prover_address: AztecAddress::zero(), + }, + is_execution_request: true, + }; + reader.finish(); + + assert(contract_address.eq(item.contract_address)); + assert(function_selector.eq(item.function_data.selector)); + + assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter); + // We increment the sideffect counter by one, to account for the call itself being a side effect. + self.side_effect_counter = self.side_effect_counter + 1; + + assert(args_hash == item.public_inputs.args_hash); + + // Assert that the call context of the enqueued call generated by the oracle matches our request. + // We are issuing a regular call which is not delegate, static, or deployment. We also constrain + // the msg_sender in the nested call to be equal to our address, and the execution context address + // for the nested call to be equal to the address we actually called. + assert(item.public_inputs.call_context.is_delegate_call == false); + assert(item.public_inputs.call_context.is_static_call == false); + assert(item.public_inputs.call_context.is_contract_deployment == false); + assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)); + assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address)); + + self.public_call_stack_hashes.push(item.hash()); + } +} diff --git a/yarn-project/aztec-nr/aztec/src/context/public_context.nr b/yarn-project/aztec-nr/aztec/src/context/public_context.nr new file mode 100644 index 00000000000..2309a906d22 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/context/public_context.nr @@ -0,0 +1,237 @@ +use crate::{ + context::inputs::PublicContextInputs, + messaging::process_l1_to_l2_message, + oracle::{ + arguments, + public_call::call_public_function_internal, + }, +}; +use dep::protocol_types::{ + abis::{ + global_variables::GlobalVariables, + function_selector::FunctionSelector, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs, + side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + }, + address::{ + AztecAddress, + EthAddress, + }, + constants::{ + MAX_NEW_COMMITMENTS_PER_CALL, + MAX_NEW_L2_TO_L1_MSGS_PER_CALL, + MAX_NEW_NULLIFIERS_PER_CALL, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, + NUM_FIELDS_PER_SHA256, + RETURN_VALUES_LENGTH, + }, + contrakt::{ + storage_read::StorageRead, + storage_update_request::StorageUpdateRequest, + }, + hash::hash_args, + header::Header, + utils::reader::Reader, +}; + +struct PublicContext { + inputs: PublicContextInputs, + side_effect_counter: u32, + + args_hash : Field, + return_values : BoundedVec, + + contract_storage_update_requests: BoundedVec, + contract_storage_reads: BoundedVec, + public_call_stack_hashes: BoundedVec, + + new_commitments: BoundedVec, + new_nullifiers: BoundedVec, + + new_l2_to_l1_msgs: BoundedVec, + + unencrypted_logs_hash: BoundedVec, + unencrypted_logs_preimages_length: Field, + + // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block + // previous to the one in which the tx is included. + historical_header: Header, + prover_address: AztecAddress, +} + +impl PublicContext { + pub fn new(inputs: PublicContextInputs, args_hash: Field) -> PublicContext { + let empty_storage_read = StorageRead::empty(); + let empty_storage_update = StorageUpdateRequest::empty(); + PublicContext { + inputs: inputs, + side_effect_counter: inputs.call_context.start_side_effect_counter, + + args_hash: args_hash, + return_values: BoundedVec::new(0), + + contract_storage_update_requests: BoundedVec::new(empty_storage_update), + contract_storage_reads: BoundedVec::new(empty_storage_read), + public_call_stack_hashes: BoundedVec::new(0), + + new_commitments: BoundedVec::new(SideEffect::empty()), + new_nullifiers: BoundedVec::new(SideEffectLinkedToNoteHash::empty()), + + new_l2_to_l1_msgs: BoundedVec::new(0), + + + unencrypted_logs_hash: BoundedVec::new(0), + unencrypted_logs_preimages_length: 0, + + historical_header: inputs.historical_header, + prover_address: AztecAddress::zero(), + + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + // encrypted_logs_preimages: Vec::new(), + // unencrypted_logs_preimages: Vec::new(), + } + } + + pub fn msg_sender(self) -> AztecAddress { + self.inputs.call_context.msg_sender + } + + pub fn this_address(self) -> AztecAddress { + self.inputs.call_context.storage_contract_address + } + + pub fn this_portal_address(self) -> EthAddress { + self.inputs.call_context.portal_contract_address + } + + pub fn chain_id(self) -> Field { + self.inputs.public_global_variables.chain_id + } + + pub fn version(self) -> Field { + self.inputs.public_global_variables.version + } + + pub fn selector(self) -> FunctionSelector { + self.inputs.call_context.function_selector + } + + pub fn block_number(self) -> Field { + self.inputs.public_global_variables.block_number + } + + pub fn timestamp(self) -> Field { + self.inputs.public_global_variables.timestamp + } + + pub fn coinbase(self) -> EthAddress { + self.inputs.public_global_variables.coinbase + } + + pub fn fee_recipient(self) -> AztecAddress { + self.inputs.public_global_variables.fee_recipient + } + + pub fn finish(self) -> PublicCircuitPublicInputs { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let unencrypted_log_preimages_length = 0; + + + // Compute the public call stack hashes + let pub_circuit_pub_inputs = PublicCircuitPublicInputs { + call_context: self.inputs.call_context, // Done + args_hash: self.args_hash, // Done + contract_storage_update_requests: self.contract_storage_update_requests.storage, + contract_storage_reads: self.contract_storage_reads.storage, + return_values: self.return_values.storage, + new_commitments: self.new_commitments.storage, + new_nullifiers: self.new_nullifiers.storage, + public_call_stack_hashes: self.public_call_stack_hashes.storage, + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + unencrypted_logs_hash: unencrypted_logs_hash, + unencrypted_log_preimages_length: unencrypted_log_preimages_length, + historical_header: self.inputs.historical_header, + prover_address: self.prover_address, + }; + pub_circuit_pub_inputs + } + + pub fn push_new_note_hash(&mut self, note_hash: Field) { + let side_effect = SideEffect { + value: note_hash, + counter: self.side_effect_counter + }; + self.new_commitments.push(side_effect); + self.side_effect_counter = self.side_effect_counter + 1; + } + + pub fn push_new_nullifier(&mut self, nullifier: Field, _nullified_commitment: Field) { + let side_effect = SideEffectLinkedToNoteHash { + value: nullifier, + note_hash: 0, // cannot nullify pending notes in public context + counter: self.side_effect_counter + }; + self.new_nullifiers.push(side_effect); + self.side_effect_counter = self.side_effect_counter + 1; + } + + pub fn message_portal(&mut self, content: Field) { + self.new_l2_to_l1_msgs.push(content); + } + + // PrivateContextInputs must be temporarily passed in to prevent too many unknowns + // Note this returns self to get around an issue where mutable structs do not maintain mutations unless reassigned + pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field) { + let this = (*self).this_address(); + let nullifier = process_l1_to_l2_message(self.historical_header.state.l1_to_l2_message_tree.root, this, self.this_portal_address(), self.chain_id(), self.version(), msg_key, content, secret); + + // Push nullifier (and the "commitment" corresponding to this can be "empty") + self.push_new_nullifier(nullifier, 0) + } + + pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { + let _void1 = self; + let _void2 = log; + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + } + + pub fn accumulate_unencrypted_logs(&mut self, log: T) { + let _void1 = self; + let _void2 = log; + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + } + + pub fn call_public_function( + _self: Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT], + ) -> [Field; RETURN_VALUES_LENGTH] { + let args_hash = hash_args(args); + assert(args_hash == arguments::pack_arguments(args)); + call_public_function_internal( + contract_address, + function_selector, + args_hash, + ) + } + + pub fn call_public_function_no_args( + _self: Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + ) -> [Field; RETURN_VALUES_LENGTH] { + call_public_function_internal( + contract_address, + function_selector, + 0, + ) + } + +} diff --git a/yarn-project/aztec-nr/aztec/src/hasher.nr b/yarn-project/aztec-nr/aztec/src/hasher.nr new file mode 100644 index 00000000000..fcfd27a74ac --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/hasher.nr @@ -0,0 +1,30 @@ +use dep::protocol_types::{ + hash::hash_args, + traits::Hash, +}; + +struct Hasher { + fields: [Field], +} + +impl Hash for Hasher { + fn hash(self) -> Field { + hash_args(self.fields) + } +} + +impl Hasher { + pub fn new()-> Self { + Self { fields: [] } + } + + pub fn add(&mut self, field: Field) { + self.fields = self.fields.push_back(field); + } + + pub fn add_multiple(&mut self, fields: [Field; N]) { + for i in 0..N { + self.fields = self.fields.push_back(fields[i]); + } + } +} diff --git a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr index 055a6222ebe..5b4469b20f5 100644 --- a/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr @@ -27,11 +27,10 @@ pub fn prove_contract_inclusion( contract_class_id: ContractClassId, initialization_hash: Field, portal_contract_address: EthAddress, - block_number: u32, // The block at which we'll prove that the public value exists context: PrivateContext ) -> AztecAddress { - // 1) Get block header from oracle and ensure that the block is included in the archive. - // let block_header = context.get_header.at(block_number); + // 1) Get block header from context + // let block_header = context.historical_header; // 2) Compute the contract address let contract_address = AztecAddress::compute_from_public_key( @@ -64,3 +63,29 @@ pub fn prove_contract_inclusion( contract_address } + +pub fn prove_contract_inclusion_at( + public_key: GrumpkinPoint, + contract_address_salt: Field, + contract_class_id: ContractClassId, + initialization_hash: Field, + portal_contract_address: EthAddress, + block_number: u32, + context: PrivateContext +) -> AztecAddress { + // 1) Get block header from oracle and ensure that the block is included in the archive. + let header = context.get_header_at(block_number); + + // 2) Compute the contract address + let contract_address = AztecAddress::compute_from_public_key( + public_key, + contract_class_id, + contract_address_salt, + initialization_hash, + portal_contract_address + ); + + // TODO(@spalladino): See above func to impl + + contract_address +} diff --git a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr index facb1261ba5..b4170fde8c9 100644 --- a/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/note_inclusion.nr @@ -1,40 +1,38 @@ use dep::std::merkle::compute_merkle_root; +use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, note::{ utils::compute_note_hash_for_consumption, - note_header::NoteHeader, note_interface::NoteInterface, }, oracle::get_membership_witness::get_note_hash_membership_witness, }; -pub fn prove_note_commitment_inclusion( - note_commitment: Field, - block_number: u32, // The block at which we'll prove that the note exists - context: PrivateContext -) { - // 1) Get block header from oracle and ensure that the block is included in the archive. - let header = context.get_header_at(block_number); +pub fn _note_inclusion(note: Note, header: Header) where Note: NoteInterface { + // 1) Compute note_hash + let note_hash = compute_note_hash_for_consumption(note); // 2) Get the membership witness of the note in the note hash tree - let witness = get_note_hash_membership_witness(block_number, note_commitment); + let witness = get_note_hash_membership_witness(header.global_variables.block_number as u32, note_hash); // 3) Prove that the commitment is in the note hash tree - assert( - header.state.partial.note_hash_tree.root - == compute_merkle_root(note_commitment, witness.index, witness.path), "Proving note inclusion failed" + assert_eq( + header.state.partial.note_hash_tree.root, compute_merkle_root(note_hash, witness.index, witness.path), "Proving note inclusion failed" ); - // --> Now we have traversed the trees all the way up to archive root. } -pub fn prove_note_inclusion( - note_with_header: Note, +pub fn prove_note_inclusion(note: Note, context: PrivateContext) where Note: NoteInterface { + _note_inclusion(note, context.historical_header); +} + +pub fn prove_note_inclusion_at( + note: Note, block_number: u32, // The block at which we'll prove that the note exists context: PrivateContext ) where Note: NoteInterface { - let note_commitment = compute_note_hash_for_consumption(note_with_header); + let header = context.get_header_at(block_number); - prove_note_commitment_inclusion(note_commitment, block_number, context); + _note_inclusion(note, header); } diff --git a/yarn-project/aztec-nr/aztec/src/history/note_validity.nr b/yarn-project/aztec-nr/aztec/src/history/note_validity.nr index fb5ed5b830b..916e6ff16ef 100644 --- a/yarn-project/aztec-nr/aztec/src/history/note_validity.nr +++ b/yarn-project/aztec-nr/aztec/src/history/note_validity.nr @@ -2,17 +2,31 @@ use crate::{ context::PrivateContext, history::{ note_inclusion::prove_note_inclusion, + note_inclusion::_note_inclusion, nullifier_non_inclusion::prove_note_not_nullified, + nullifier_non_inclusion::_nullifier_non_inclusion, + }, + note::{ + utils::compute_siloed_nullifier, + note_interface::NoteInterface, }, - note::note_interface::NoteInterface, }; +pub fn prove_note_validity(note: Note, context: &mut PrivateContext) where Note: NoteInterface { + prove_note_inclusion(note, *context); + prove_note_not_nullified(note, context); +} + // A helper function that proves that a note is valid at the given block number -pub fn prove_note_validity( - note_with_header: Note, - block_number: u32, // The block at which we'll prove that the note exists +pub fn prove_note_validity_at( + note: Note, + block_number: u32, context: &mut PrivateContext ) where Note: NoteInterface { - prove_note_inclusion(note_with_header, block_number, *context); - prove_note_not_nullified(note_with_header, block_number, context); + // We are calling the internal functions here because we want to avoid calling get_header_at twice + let header = context.get_header_at(block_number); + _note_inclusion(note, header); + + let nullifier = compute_siloed_nullifier(note, context); + _nullifier_non_inclusion(nullifier, header); } diff --git a/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 1d61313825e..6a1a28d6ac5 100644 --- a/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -1,28 +1,26 @@ use dep::std::merkle::compute_merkle_root; +use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, + note::{ + utils::compute_siloed_nullifier, + note_interface::NoteInterface, + }, }; -pub fn prove_nullifier_inclusion( - nullifier: Field, - block_number: u32, // The block at which we'll prove that the note exists - context: PrivateContext -) { - // 1) Get block header from oracle and ensure that the block hash is included in the archive. - let header = context.get_header_at(block_number); - - // 2) Get the membership witness of the nullifier - let witness = get_nullifier_membership_witness(block_number, nullifier); +fn _nullifier_inclusion(nullifier: Field, header: Header) { + // 1) Get the membership witness of the nullifier + let witness = get_nullifier_membership_witness(header.global_variables.block_number as u32, nullifier); - // 3) Check that the witness we obtained matches the nullifier + // 2) Check that the witness we obtained matches the nullifier assert(witness.leaf_preimage.nullifier == nullifier, "Nullifier does not match value in witness"); - // 4) Compute the nullifier tree leaf + // 3) Compute the nullifier tree leaf let nullifier_leaf = witness.leaf_preimage.hash(); - // 5) Prove that the nullifier is in the nullifier tree + // 4) Prove that the nullifier is in the nullifier tree assert( header.state.partial.nullifier_tree.root == compute_merkle_root(nullifier_leaf, witness.index, witness.path), "Proving nullifier inclusion failed" @@ -30,3 +28,37 @@ pub fn prove_nullifier_inclusion( // --> Now we have traversed the trees all the way up to archive root and verified that the nullifier // was not yet included in the nullifier tree. } + +pub fn prove_nullifier_inclusion(nullifier: Field, context: PrivateContext) { + _nullifier_inclusion(nullifier, context.historical_header); +} + +pub fn prove_nullifier_inclusion_at( + nullifier: Field, + block_number: u32, // The block at which we'll prove that the note exists + context: PrivateContext +) { + let header = context.get_header_at(block_number); + + _nullifier_inclusion(nullifier, header); +} + +pub fn prove_note_is_nullified( + note: Note, + context: &mut PrivateContext +) where Note: NoteInterface { + let nullifier = compute_siloed_nullifier(note, context); + + _nullifier_inclusion(nullifier, context.historical_header); +} + +pub fn prove_note_is_nullified_at( + note: Note, + block_number: u32, + context: &mut PrivateContext +) where Note: NoteInterface { + let nullifier = compute_siloed_nullifier(note, context); + let header = context.get_header_at(block_number); + + _nullifier_inclusion(nullifier, header); +} diff --git a/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index acc0d362f47..5568321fbd2 100644 --- a/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -1,10 +1,10 @@ use dep::std::merkle::compute_merkle_root; +use dep::protocol_types::header::Header; use crate::{ context::PrivateContext, note::{ utils::compute_siloed_nullifier, - note_header::NoteHeader, note_interface::NoteInterface, }, oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness, @@ -14,16 +14,9 @@ use crate::{ }, }; -pub fn prove_nullifier_non_inclusion( - nullifier: Field, - block_number: u32, // The block at which we'll prove that the nullifier does not exists - context: PrivateContext -) { - // 1) Get block header from oracle and ensure that the block is included in the archive. - let header = context.get_header_at(block_number); - - // 2) Get the membership witness of a low nullifier of the nullifier - let witness = get_low_nullifier_membership_witness(block_number, nullifier); +pub fn _nullifier_non_inclusion(nullifier: Field, header: Header) { + // 1) Get the membership witness of a low nullifier of the nullifier + let witness = get_low_nullifier_membership_witness(header.global_variables.block_number as u32, nullifier); // 3) Prove that the nullifier is not included in the nullifier tree @@ -49,12 +42,32 @@ pub fn prove_nullifier_non_inclusion( // was not yet included in the nullifier tree. } +pub fn prove_nullifier_not_included(nullifier: Field, context: PrivateContext) { + _nullifier_non_inclusion(nullifier, context.historical_header); +} + +pub fn prove_nullifier_not_included_at(nullifier: Field, block_number: u32, context: PrivateContext) { + let header = context.get_header_at(block_number); + + _nullifier_non_inclusion(nullifier, header); +} + pub fn prove_note_not_nullified( - note_with_header: Note, + note: Note, + context: &mut PrivateContext +) where Note: NoteInterface { + let nullifier = compute_siloed_nullifier(note, context); + + _nullifier_non_inclusion(nullifier, context.historical_header); +} + +pub fn prove_note_not_nullified_at( + note: Note, block_number: u32, // The block at which we'll prove that the note was not nullified context: &mut PrivateContext ) where Note: NoteInterface { - let nullifier = compute_siloed_nullifier(note_with_header, context); + let nullifier = compute_siloed_nullifier(note, context); + let header = context.get_header_at(block_number); - prove_nullifier_non_inclusion(nullifier, block_number, *context); + _nullifier_non_inclusion(nullifier, header); } diff --git a/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr b/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr index ad14fb77cb3..fbbfe95b9a9 100644 --- a/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr +++ b/yarn-project/aztec-nr/aztec/src/history/public_value_inclusion.nr @@ -1,6 +1,10 @@ use dep::protocol_types::{ constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, + header::Header, hash::pedersen_hash, + address::{ + AztecAddress + }, }; use dep::std::merkle::compute_merkle_root; @@ -8,30 +12,29 @@ use crate::{ context::PrivateContext, oracle::get_public_data_witness::{ get_public_data_witness, - PublicDataWitness, }, utils::{ full_field_less_than, }, }; -pub fn prove_public_value_inclusion( - value: Field, // The value that we want to prove is in the public data tree - storage_slot: Field, // The storage slot in which the value is stored - block_number: u32, // The block at which we'll prove that the note exists - context: PrivateContext +fn _public_value_inclusion( + value: Field, + storage_slot: Field, + contract_address: AztecAddress, + header: Header ) { - // 1) Get block header from oracle and ensure that the block hash is included in the archive. - let header = context.get_header_at(block_number); - - // 2) Compute the leaf slot by siloing the storage slot with our own address + // 1) Compute the leaf slot by siloing the storage slot with the contract address let public_value_leaf_slot = pedersen_hash( - [context.this_address().to_field(), storage_slot], + [contract_address.to_field(), storage_slot], GENERATOR_INDEX__PUBLIC_LEAF_INDEX ); // 3) Get the membership witness of the slot - let witness = get_public_data_witness(block_number, public_value_leaf_slot); + let witness = get_public_data_witness( + header.global_variables.block_number as u32, + public_value_leaf_slot + ); // 4) Check that the witness matches the corresponding public_value let preimage = witness.leaf_preimage; @@ -59,3 +62,29 @@ pub fn prove_public_value_inclusion( // --> Now we have traversed the trees all the way up to archive root and that way verified that a specific // `value` was really set in a given contract storage slot at block `block_number` in public data tree. } + +pub fn prove_public_value_inclusion( + value: Field, // The value that we want to prove is in the public data tree + storage_slot: Field, // The storage slot in which the value is stored + contract_address: AztecAddress, // The contract we want to look into + context: PrivateContext +) { + _public_value_inclusion( + value, + storage_slot, + contract_address, + context.historical_header + ); +} + +pub fn prove_public_value_inclusion_at( + value: Field, // The value that we want to prove is in the public data tree + storage_slot: Field, // The storage slot in which the value is stored + contract_address: AztecAddress, // The contract we want to look into + block_number: u32, // The block at which we'll prove that the note exists + context: PrivateContext +) { + let header = context.get_header_at(block_number); + + _public_value_inclusion(value, storage_slot, contract_address, header); +} diff --git a/yarn-project/aztec-nr/aztec/src/lib.nr b/yarn-project/aztec-nr/aztec/src/lib.nr index 7a8531601c4..4b02952d76a 100644 --- a/yarn-project/aztec-nr/aztec/src/lib.nr +++ b/yarn-project/aztec-nr/aztec/src/lib.nr @@ -1,6 +1,7 @@ -mod abi; +mod avm; mod context; mod hash; +mod hasher; mod history; mod key; mod log; diff --git a/yarn-project/aztec-nr/aztec/src/messaging.nr b/yarn-project/aztec-nr/aztec/src/messaging.nr index 78dc5d33eec..c75febd0a0e 100644 --- a/yarn-project/aztec-nr/aztec/src/messaging.nr +++ b/yarn-project/aztec-nr/aztec/src/messaging.nr @@ -3,7 +3,6 @@ mod l1_to_l2_message_getter_data; use l1_to_l2_message_getter_data::make_l1_to_l2_message_getter_data; -use crate::abi::PublicContextInputs; use crate::oracle::get_l1_to_l2_message::get_l1_to_l2_message_call; use dep::std::merkle::compute_merkle_root; diff --git a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr index b94d8a146ce..84326f9ace6 100644 --- a/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr +++ b/yarn-project/aztec-nr/aztec/src/note/lifecycle.nr @@ -1,4 +1,3 @@ -use crate::abi::PublicContextInputs; use crate::context::{ PrivateContext, PublicContext, @@ -35,11 +34,7 @@ pub fn create_note( } } -pub fn create_note_hash_from_public( - context: &mut PublicContext, - storage_slot: Field, - note: &mut Note -) where Note: NoteInterface { +pub fn create_note_hash_from_public(context: &mut PublicContext, storage_slot: Field, note: &mut Note) where Note: NoteInterface { let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; diff --git a/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr b/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr index 98a0ab385a2..489fd383082 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle/call_private_function.nr @@ -1,7 +1,10 @@ use dep::protocol_types::{ - abis::function_selector::FunctionSelector, + abis::{ + function_selector::FunctionSelector, + private_call_stack_item::PrivateCallStackItem, + }, address::AztecAddress, - constants::CALL_PRIVATE_FUNCTION_RETURN_SIZE, + constants::PRIVATE_CALL_STACK_ITEM_LENGTH, }; #[oracle(callPrivateFunction)] @@ -10,18 +13,20 @@ fn call_private_function_oracle( _function_selector: FunctionSelector, _args_hash: Field, _start_side_effect_counter: u32 -) -> [Field; CALL_PRIVATE_FUNCTION_RETURN_SIZE] {} +) -> [Field; PRIVATE_CALL_STACK_ITEM_LENGTH] {} unconstrained pub fn call_private_function_internal( contract_address: AztecAddress, function_selector: FunctionSelector, args_hash: Field, start_side_effect_counter: u32 -) -> [Field; CALL_PRIVATE_FUNCTION_RETURN_SIZE] { - call_private_function_oracle( +) -> PrivateCallStackItem { + let fields = call_private_function_oracle( contract_address, function_selector, args_hash, start_side_effect_counter - ) + ); + + PrivateCallStackItem::deserialize(fields) } diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/set.nr b/yarn-project/aztec-nr/aztec/src/state_vars/set.nr index 3b0dd845b6e..7144bbe3013 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/set.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/set.nr @@ -1,5 +1,4 @@ use dep::std::option::Option; -use crate::abi::PublicContextInputs; use dep::protocol_types::{ constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL}, abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash}, diff --git a/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr b/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr index af4925f47ff..e42b107bbd7 100644 --- a/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr +++ b/yarn-project/aztec-nr/aztec/src/state_vars/stable_public_state.nr @@ -50,19 +50,15 @@ impl StablePublicState { // Read the value from storage (using the public tree) let fields = storage_read(self.storage_slot); - // TODO: The block_number here can be removed when using the current header in the membership proof. - let block_number = private_context.get_header().global_variables.block_number; - // Loop over the fields and prove their inclusion in the public tree for i in 0..fields.len() { // TODO: Update membership proofs to use current header (Requires #4179) // Currently executing unnecessary computation: - // - a membership proof of the header(block_number) in the history // - a membership proof of the value in the public tree of the header prove_public_value_inclusion( fields[i], self.storage_slot + i, - block_number as u32, + (*private_context).this_address(), (*private_context), ) } diff --git a/yarn-project/aztec-nr/aztec/src/utils.nr b/yarn-project/aztec-nr/aztec/src/utils.nr index a0936a3015b..9d66e257b9c 100644 --- a/yarn-project/aztec-nr/aztec/src/utils.nr +++ b/yarn-project/aztec-nr/aztec/src/utils.nr @@ -16,46 +16,3 @@ pub fn full_field_less_than(lhs: Field, rhs: Field) -> bool { pub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool { rhs.lt(lhs) } - -// TODO(benesjan): also in circuits. NUKE THIS! -struct Reader { - data: [Field; N], - offset: Field, -} - -impl Reader { - pub fn new(data: [Field; N]) -> Self { - Self { data, offset: 0 } - } - - pub fn read(&mut self) -> Field { - let result = self.data[self.offset]; - self.offset += 1; - result - } - - pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] { - for i in 0..K { - result[i] = self.data[self.offset + i]; - } - self.offset += K; - result - } - - // TODO(#4394) - pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T { - let result = deserialise(self.read_array([0; K])); - result - } - - pub fn read_struct_array(&mut self, deserialise: fn([Field; K]) -> T, mut result: [T; C]) -> [T; C] { - for i in 0..C { - result[i] = self.read_struct(deserialise); - } - result - } - - pub fn finish(self) { - assert(self.offset == self.data.len(), "Reader did not read all data"); - } -} diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index c3e3c461005..7af38fa4dc6 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -9,6 +9,7 @@ "./abi": "./dest/api/abi.js", "./account": "./dest/api/account.js", "./aztec_address": "./dest/api/aztec_address.js", + "./deployment": "./dest/api/deployment.js", "./eth_address": "./dest/api/eth_address.js", "./ethereum": "./dest/api/ethereum.js", "./fields": "./dest/api/fields.js", @@ -51,6 +52,7 @@ "@aztec/circuits.js": "workspace:^", "@aztec/ethereum": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@aztec/types": "workspace:^", "tslib": "^2.4.0" }, diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index e48e48dc161..954ab75846a 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -7,7 +7,7 @@ import { AccountContract } from '../account/contract.js'; import { Salt } from '../account/index.js'; import { AccountInterface } from '../account/interface.js'; import { DefaultWaitOpts, DeployMethod, WaitOpts } from '../contract/index.js'; -import { ContractDeployer } from '../contract_deployer/index.js'; +import { ContractDeployer } from '../deployment/index.js'; import { waitForAccountSynch } from '../utils/account.js'; import { generatePublicKey } from '../utils/index.js'; import { AccountWalletWithPrivateKey } from '../wallet/index.js'; diff --git a/yarn-project/aztec.js/src/api/deployment.ts b/yarn-project/aztec.js/src/api/deployment.ts new file mode 100644 index 00000000000..e6e2ad24521 --- /dev/null +++ b/yarn-project/aztec.js/src/api/deployment.ts @@ -0,0 +1,3 @@ +export { registerContractClass } from '../deployment/register_class.js'; +export { broadcastPrivateFunction, broadcastUnconstrainedFunction } from '../deployment/broadcast_function.js'; +export { deployInstance } from '../deployment/deploy_instance.js'; diff --git a/yarn-project/aztec.js/src/contract/unsafe_contract.ts b/yarn-project/aztec.js/src/contract/unsafe_contract.ts new file mode 100644 index 00000000000..d010d7121c7 --- /dev/null +++ b/yarn-project/aztec.js/src/contract/unsafe_contract.ts @@ -0,0 +1,19 @@ +import { ContractArtifact } from '@aztec/foundation/abi'; +import { ContractInstanceWithAddress } from '@aztec/types/contracts'; + +import { Wallet } from '../wallet/index.js'; +import { ContractBase } from './contract_base.js'; + +/** Unsafe constructor for ContractBase that bypasses the check that the instance is registered in the wallet. */ +export class UnsafeContract extends ContractBase { + constructor( + /** The deployed contract instance definition. */ + instance: ContractInstanceWithAddress, + /** The Application Binary Interface for the contract. */ + artifact: ContractArtifact, + /** The wallet used for interacting with this contract. */ + wallet: Wallet, + ) { + super(instance, artifact, wallet); + } +} diff --git a/yarn-project/aztec.js/src/deployment/broadcast_function.ts b/yarn-project/aztec.js/src/deployment/broadcast_function.ts new file mode 100644 index 00000000000..785cd1d2619 --- /dev/null +++ b/yarn-project/aztec.js/src/deployment/broadcast_function.ts @@ -0,0 +1,118 @@ +import { + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + computeArtifactFunctionTree, + computeArtifactFunctionTreeRoot, + computeArtifactMetadataHash, + computeFunctionArtifactHash, + computePrivateFunctionsTree, + getContractClassFromArtifact, +} from '@aztec/circuits.js'; +import { ContractArtifact, FunctionSelector, FunctionType, bufferAsFields } from '@aztec/foundation/abi'; +import { padArrayEnd } from '@aztec/foundation/collection'; +import { Fr } from '@aztec/foundation/fields'; + +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { Wallet } from '../wallet/index.js'; +import { getRegistererContract } from './protocol_contracts.js'; + +/** + * Sets up a call to broadcast a private function's bytecode via the ClassRegisterer contract. + * Note that this is not required for users to call the function, but is rather a convenience to make + * this code publicly available so dapps or wallets do not need to redistribute it. + * @param wallet - Wallet to send the transaction. + * @param artifact - Contract artifact that contains the function to be broadcast. + * @param selector - Selector of the function to be broadcast. + * @returns A ContractFunctionInteraction object that can be used to send the transaction. + */ +export function broadcastPrivateFunction( + wallet: Wallet, + artifact: ContractArtifact, + selector: FunctionSelector, +): ContractFunctionInteraction { + const contractClass = getContractClassFromArtifact(artifact); + const privateFunction = contractClass.privateFunctions.find(fn => fn.selector.equals(selector)); + if (!privateFunction) { + throw new Error(`Private function with selector ${selector.toString()} not found`); + } + const privateFunctionArtifact = artifact.functions.find(fn => + FunctionSelector.fromNameAndParameters(fn).equals(selector), + )!; + + // TODO(@spalladino): The following is computing the unconstrained root hash twice. + // Feels like we need a nicer API for returning a hash along with all its preimages, + // since it's common to provide all hash preimages to a function that verifies them. + const artifactMetadataHash = computeArtifactMetadataHash(artifact); + const unconstrainedArtifactFunctionTreeRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.OPEN); + + // We need two sibling paths because private function information is split across two trees: + // The "private function tree" captures the selectors and verification keys, and is used in the kernel circuit for verifying the proof generated by the app circuit. + // The "artifact tree" captures function bytecode and metadata, and is used by the pxe to check that its executing the code it's supposed to be executing, but it never goes into circuits. + const privateFunctionTreePath = computePrivateFunctionsTree(contractClass.privateFunctions).getSiblingPath(0); + const artifactFunctionTreePath = computeArtifactFunctionTree(artifact, FunctionType.SECRET)!.getSiblingPath(0); + + const vkHash = privateFunction.vkHash; + const metadataHash = computeFunctionArtifactHash(privateFunctionArtifact); + const bytecode = bufferAsFields( + Buffer.from(privateFunctionArtifact.bytecode, 'hex'), + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + ); + + const registerer = getRegistererContract(wallet); + return registerer.methods.broadcast_private_function( + contractClass.id, + Fr.fromBufferReduce(artifactMetadataHash), + Fr.fromBufferReduce(unconstrainedArtifactFunctionTreeRoot), + privateFunctionTreePath.map(Fr.fromBufferReduce), + padArrayEnd(artifactFunctionTreePath.map(Fr.fromBufferReduce), Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + // eslint-disable-next-line camelcase + { selector, metadata_hash: Fr.fromBufferReduce(metadataHash), bytecode, vk_hash: vkHash }, + ); +} + +/** + * Sets up a call to broadcast an unconstrained function's bytecode via the ClassRegisterer contract. + * Note that this is not required for users to call the function, but is rather a convenience to make + * this code publicly available so dapps or wallets do not need to redistribute it. + * @param wallet - Wallet to send the transaction. + * @param artifact - Contract artifact that contains the function to be broadcast. + * @param selector - Selector of the function to be broadcast. + * @returns A ContractFunctionInteraction object that can be used to send the transaction. + */ +export function broadcastUnconstrainedFunction( + wallet: Wallet, + artifact: ContractArtifact, + selector: FunctionSelector, +): ContractFunctionInteraction { + const functionArtifactIndex = artifact.functions.findIndex( + fn => fn.functionType === FunctionType.UNCONSTRAINED && FunctionSelector.fromNameAndParameters(fn).equals(selector), + ); + if (functionArtifactIndex < 0) { + throw new Error(`Unconstrained function with selector ${selector.toString()} not found`); + } + const functionArtifact = artifact.functions[functionArtifactIndex]; + + // TODO(@spalladino): Same comment as above on computing duplicated hashes. + const artifactMetadataHash = computeArtifactMetadataHash(artifact); + const privateArtifactFunctionTreeRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.SECRET); + const functionTreePath = computeArtifactFunctionTree(artifact, FunctionType.UNCONSTRAINED)!.getSiblingPath( + functionArtifactIndex, + ); + + const contractClassId = getContractClassFromArtifact(artifact).id; + const metadataHash = computeFunctionArtifactHash(functionArtifact); + const bytecode = bufferAsFields( + Buffer.from(functionArtifact.bytecode, 'hex'), + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + ); + + const registerer = getRegistererContract(wallet); + return registerer.methods.broadcast_unconstrained_function( + contractClassId, + Fr.fromBufferReduce(artifactMetadataHash), + Fr.fromBufferReduce(privateArtifactFunctionTreeRoot), + padArrayEnd(functionTreePath.map(Fr.fromBufferReduce), Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + // eslint-disable-next-line camelcase + { selector, metadata_hash: Fr.fromBufferReduce(metadataHash), bytecode }, + ); +} diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts b/yarn-project/aztec.js/src/deployment/contract_deployer.test.ts similarity index 100% rename from yarn-project/aztec.js/src/contract_deployer/contract_deployer.test.ts rename to yarn-project/aztec.js/src/deployment/contract_deployer.test.ts diff --git a/yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts b/yarn-project/aztec.js/src/deployment/contract_deployer.ts similarity index 100% rename from yarn-project/aztec.js/src/contract_deployer/contract_deployer.ts rename to yarn-project/aztec.js/src/deployment/contract_deployer.ts diff --git a/yarn-project/aztec.js/src/deployment/deploy_instance.ts b/yarn-project/aztec.js/src/deployment/deploy_instance.ts new file mode 100644 index 00000000000..21f49fe07c9 --- /dev/null +++ b/yarn-project/aztec.js/src/deployment/deploy_instance.ts @@ -0,0 +1,28 @@ +import { ContractInstanceWithAddress } from '@aztec/types/contracts'; + +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { Wallet } from '../wallet/index.js'; +import { getDeployerContract } from './protocol_contracts.js'; + +/** + * Sets up a call to the canonical deployer contract to publicly deploy a contract instance. + * @param wallet - The wallet to use for the deployment. + * @param instance - The instance to deploy. + * @param opts - Additional options. + */ +export function deployInstance( + wallet: Wallet, + instance: ContractInstanceWithAddress, + opts: { /** Set to true to *not* mix in the deployer into the address. */ universalDeploy?: boolean } = {}, +): ContractFunctionInteraction { + const deployer = getDeployerContract(wallet); + const { salt, contractClassId, portalContractAddress, publicKeysHash } = instance; + return deployer.methods.deploy( + salt, + contractClassId, + instance.initializationHash, + portalContractAddress, + publicKeysHash, + !!opts.universalDeploy, + ); +} diff --git a/yarn-project/aztec.js/src/contract_deployer/index.ts b/yarn-project/aztec.js/src/deployment/index.ts similarity index 100% rename from yarn-project/aztec.js/src/contract_deployer/index.ts rename to yarn-project/aztec.js/src/deployment/index.ts diff --git a/yarn-project/aztec.js/src/deployment/protocol_contracts.ts b/yarn-project/aztec.js/src/deployment/protocol_contracts.ts new file mode 100644 index 00000000000..c7d59c59d63 --- /dev/null +++ b/yarn-project/aztec.js/src/deployment/protocol_contracts.ts @@ -0,0 +1,17 @@ +import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer'; +import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer'; + +import { UnsafeContract } from '../contract/unsafe_contract.js'; +import { Wallet } from '../wallet/index.js'; + +/** Returns a Contract wrapper for the class registerer. */ +export function getRegistererContract(wallet: Wallet) { + const { artifact, instance } = getCanonicalClassRegisterer(); + return new UnsafeContract(instance, artifact, wallet); +} + +/** Returns a Contract wrapper for the instance deployer. */ +export function getDeployerContract(wallet: Wallet) { + const { artifact, instance } = getCanonicalInstanceDeployer(); + return new UnsafeContract(instance, artifact, wallet); +} diff --git a/yarn-project/aztec.js/src/deployment/register_class.ts b/yarn-project/aztec.js/src/deployment/register_class.ts new file mode 100644 index 00000000000..4ac0532bef5 --- /dev/null +++ b/yarn-project/aztec.js/src/deployment/register_class.ts @@ -0,0 +1,15 @@ +import { MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, getContractClassFromArtifact } from '@aztec/circuits.js'; +import { ContractArtifact, bufferAsFields } from '@aztec/foundation/abi'; + +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { Wallet } from '../wallet/index.js'; +import { getRegistererContract } from './protocol_contracts.js'; + +/** Sets up a call to register a contract class given its artifact. */ +export function registerContractClass(wallet: Wallet, artifact: ContractArtifact): ContractFunctionInteraction { + const { artifactHash, privateFunctionsRoot, publicBytecodeCommitment, packedBytecode } = + getContractClassFromArtifact(artifact); + const encodedBytecode = bufferAsFields(packedBytecode, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS); + const registerer = getRegistererContract(wallet); + return registerer.methods.register(artifactHash, privateFunctionsRoot, publicBytecodeCommitment, encodedBytecode); +} diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 90f8e8d431d..14f6c88ee6e 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -31,7 +31,7 @@ export { DeploySentTx, } from './contract/index.js'; -export { ContractDeployer } from './contract_deployer/index.js'; +export { ContractDeployer } from './deployment/index.js'; export { generatePublicKey, diff --git a/yarn-project/aztec.js/tsconfig.json b/yarn-project/aztec.js/tsconfig.json index b6f148a8e0d..1d84c77d151 100644 --- a/yarn-project/aztec.js/tsconfig.json +++ b/yarn-project/aztec.js/tsconfig.json @@ -18,6 +18,9 @@ { "path": "../foundation" }, + { + "path": "../protocol-contracts" + }, { "path": "../types" } diff --git a/yarn-project/aztec/src/cli/cmds/start_archiver.ts b/yarn-project/aztec/src/cli/cmds/start_archiver.ts index 0a07c96ae6c..653636f8c8f 100644 --- a/yarn-project/aztec/src/cli/cmds/start_archiver.ts +++ b/yarn-project/aztec/src/cli/cmds/start_archiver.ts @@ -5,8 +5,10 @@ import { createArchiverRpcServer, getConfigEnvVars as getArchiverConfigEnvVars, } from '@aztec/archiver'; +import { createDebugLogger } from '@aztec/aztec.js'; import { ServerList } from '@aztec/foundation/json-rpc/server'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; +import { initStoreForRollup } from '@aztec/kv-store/utils'; import { mergeEnvVarsAndCliOptions, parseModuleOptions } from '../util.js'; @@ -20,7 +22,12 @@ export const startArchiver = async (options: any, signalHandlers: (() => Promise // merge env vars and cli options const archiverConfig = mergeEnvVarsAndCliOptions(archiverConfigEnvVars, archiverCliOptions, true); - const store = await AztecLmdbStore.open(archiverConfig.l1Contracts.rollupAddress, archiverConfig.dataDirectory); + const storeLog = createDebugLogger('aztec:archiver:lmdb'); + const store = await initStoreForRollup( + AztecLmdbStore.open(archiverConfig.dataDirectory, storeLog), + archiverConfig.l1Contracts.rollupAddress, + storeLog, + ); const archiverStore = new KVArchiverDataStore(store, archiverConfig.maxLogs); const archiver = await Archiver.createAndSync(archiverConfig, archiverStore, true); diff --git a/yarn-project/bootstrap.sh b/yarn-project/bootstrap.sh index 3d2affb3300..6df64d6c3af 100755 --- a/yarn-project/bootstrap.sh +++ b/yarn-project/bootstrap.sh @@ -42,11 +42,13 @@ yarn workspace @aztec/noir-compiler build # Builds noir contracts (TODO: move this stage pre yarn-project). Generates typescript wrappers. echo "Building contracts from noir-contracts..." yarn workspace @aztec/noir-contracts build:contracts -# Bundle compiled account contracts into accounts package +# Bundle compiled contracts into other packages echo "Copying account contracts..." yarn workspace @aztec/accounts build:copy-contracts +echo "Copying protocol contracts..." +yarn workspace @aztec/protocol-contracts build:copy-contracts # Build protocol circuits. TODO: move pre yarn-project. -echo "Building contracts from noir-protocol-circuits..." +echo "Building circuits from noir-protocol-circuits..." yarn workspace @aztec/noir-protocol-circuits build echo -e "\033[1mBuilding all packages...\033[0m" diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 2ac789ffe38..4946ead7690 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -6,7 +6,7 @@ import { Fr } from '@aztec/foundation/fields'; import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/client'; import { ContractData, ExtendedContractData } from '../../contract_data.js'; -import { AztecNode } from '../../interfaces/index.js'; +import { AztecNode } from '../../interfaces/aztec-node.js'; import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; import { L2Block } from '../../l2_block.js'; import { L2Tx } from '../../l2_tx.js'; diff --git a/yarn-project/circuit-types/src/contract_data.ts b/yarn-project/circuit-types/src/contract_data.ts index 8214618d2b0..43cec7a3e6c 100644 --- a/yarn-project/circuit-types/src/contract_data.ts +++ b/yarn-project/circuit-types/src/contract_data.ts @@ -8,6 +8,7 @@ import { serializeBufferArrayToVector, serializeToBuffer, } from '@aztec/foundation/serialize'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; /** * Used for retrieval of contract data (A3 address, portal contract address, bytecode). @@ -55,6 +56,18 @@ export interface ContractDataSource { * @returns The number of the latest L2 block processed by the implementation. */ getBlockNumber(): Promise; + + /** + * Returns the contract class for a given contract class id, or undefined if not found. + * @param id - Contract class id. + */ + getContractClass(id: Fr): Promise; + + /** + * Returns a publicly deployed contract instance given its address. + * @param address - Address of the deployed contract. + */ + getContract(address: AztecAddress): Promise; } /** @@ -253,7 +266,7 @@ export class ContractData { * @returns Encoded buffer. */ public toBuffer(): Buffer { - return serializeToBuffer(this.contractAddress, this.portalContractAddress.toBuffer20()); + return serializeToBuffer(this.contractAddress, this.portalContractAddress); } /** diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index f0d2937bd84..10123d17b7d 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -1,21 +1,165 @@ -import { Header } from '@aztec/circuits.js'; +import { + ARCHIVE_HEIGHT, + CONTRACT_TREE_HEIGHT, + Header, + L1_TO_L2_MSG_TREE_HEIGHT, + NOTE_HASH_TREE_HEIGHT, + NULLIFIER_TREE_HEIGHT, + PUBLIC_DATA_TREE_HEIGHT, +} from '@aztec/circuits.js'; import { L1ContractAddresses } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; +import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ContractData, ExtendedContractData } from '../contract_data.js'; +import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; import { L2Block } from '../l2_block.js'; import { L2Tx } from '../l2_tx.js'; import { GetUnencryptedLogsResponse, L2BlockL2Logs, LogFilter, LogType } from '../logs/index.js'; +import { MerkleTreeId } from '../merkle_tree_id.js'; +import { SiblingPath } from '../sibling_path/index.js'; import { Tx, TxHash } from '../tx/index.js'; import { SequencerConfig } from './configs.js'; -import { StateInfoProvider } from './state_info_provider.js'; +import { NullifierMembershipWitness } from './nullifier_tree.js'; +import { PublicDataWitness } from './public_data_tree.js'; + +/** Helper type for a specific L2 block number or the latest block number */ +type BlockNumber = number | 'latest'; /** * The aztec node. * We will probably implement the additional interfaces by means other than Aztec Node as it's currently a privacy leak */ -export interface AztecNode extends StateInfoProvider { +export interface AztecNode { + /** + * Find the index of the given leaf in the given tree. + * @param blockNumber - The block number at which to get the data or 'latest' for latest data + * @param treeId - The tree to search in. + * @param leafValue - The value to search for + * @returns The index of the given leaf in the given tree or undefined if not found. + */ + findLeafIndex(blockNumber: BlockNumber, treeId: MerkleTreeId, leafValue: Fr): Promise; + + /** + * Returns a sibling path for the given index in the contract tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - The index of the leaf for which the sibling path is required. + * @returns The sibling path for the leaf index. + */ + getContractSiblingPath( + blockNumber: BlockNumber, + leafIndex: bigint, + ): Promise>; + + /** + * Returns a sibling path for the given index in the nullifier tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - The index of the leaf for which the sibling path is required. + * @returns The sibling path for the leaf index. + */ + getNullifierSiblingPath( + blockNumber: BlockNumber, + leafIndex: bigint, + ): Promise>; + + /** + * Returns a sibling path for the given index in the note hash tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - The index of the leaf for which the sibling path is required. + * @returns The sibling path for the leaf index. + */ + getNoteHashSiblingPath( + blockNumber: BlockNumber, + leafIndex: bigint, + ): Promise>; + + /** + * Gets a confirmed/consumed L1 to L2 message for the given message key (throws if not found). + * and its index in the merkle tree + * @param messageKey - The message key. + * @returns The map containing the message and index. + */ + getL1ToL2MessageAndIndex(messageKey: Fr): Promise; + + /** + * Returns a sibling path for a leaf in the committed l1 to l2 data tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - Index of the leaf in the tree. + * @returns The sibling path. + */ + getL1ToL2MessageSiblingPath( + blockNumber: BlockNumber, + leafIndex: bigint, + ): Promise>; + + /** + * Returns a sibling path for a leaf in the committed historic blocks tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - Index of the leaf in the tree. + * @returns The sibling path. + */ + getArchiveSiblingPath(blockNumber: BlockNumber, leafIndex: bigint): Promise>; + + /** + * Returns a sibling path for a leaf in the committed public data tree. + * @param blockNumber - The block number at which to get the data. + * @param leafIndex - Index of the leaf in the tree. + * @returns The sibling path. + */ + getPublicDataSiblingPath( + blockNumber: BlockNumber, + leafIndex: bigint, + ): Promise>; + + /** + * Returns a nullifier membership witness for a given nullifier at a given block. + * @param blockNumber - The block number at which to get the data. + * @param nullifier - Nullifier we try to find witness for. + * @returns The nullifier membership witness (if found). + */ + getNullifierMembershipWitness( + blockNumber: BlockNumber, + nullifier: Fr, + ): Promise; + + /** + * Returns a low nullifier membership witness for a given nullifier at a given block. + * @param blockNumber - The block number at which to get the data. + * @param nullifier - Nullifier we try to find the low nullifier witness for. + * @returns The low nullifier membership witness (if found). + * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked + * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier + * we are trying to prove non-inclusion for. + */ + getLowNullifierMembershipWitness( + blockNumber: BlockNumber, + nullifier: Fr, + ): Promise; + + /** + * Returns a public data tree witness for a given leaf slot at a given block. + * @param blockNumber - The block number at which to get the data. + * @param leafSlot - The leaf slot we try to find the witness for. + * @returns The public data witness (if found). + * @remarks The witness can be used to compute the current value of the public data tree leaf. If the low leaf preimage corresponds to an + * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value + * is contained in the leaf preimage. + */ + getPublicDataTreeWitness(blockNumber: BlockNumber, leafSlot: Fr): Promise; + + /** + * Get a block specified by its number. + * @param number - The block number being requested. + * @returns The requested block. + */ + getBlock(number: number): Promise; + + /** + * Fetches the current block number. + * @returns The block number. + */ + getBlockNumber(): Promise; /** * Method to determine if the node is ready to accept transactions. * @returns - Flag indicating the readiness for tx submission. @@ -136,4 +280,16 @@ export interface AztecNode extends StateInfoProvider { * @param config - Updated configuration to be merged with the current one. */ setConfig(config: Partial): Promise; + + /** + * Returns a registered contract class given its id. + * @param id - Id of the contract class. + */ + getContractClass(id: Fr): Promise; + + /** + * Returns a publicly deployed contract instance given its address. + * @param address - Address of the deployed contract. + */ + getContract(address: AztecAddress): Promise; } diff --git a/yarn-project/circuit-types/src/interfaces/configs.ts b/yarn-project/circuit-types/src/interfaces/configs.ts index 82c6e10db16..24f8d467f13 100644 --- a/yarn-project/circuit-types/src/interfaces/configs.ts +++ b/yarn-project/circuit-types/src/interfaces/configs.ts @@ -1,17 +1,17 @@ +import { AztecAddress, EthAddress } from '@aztec/circuits.js'; + /** * The sequencer configuration. */ export interface SequencerConfig { - /** - * The number of ms to wait between polling for pending txs. - */ + /** The number of ms to wait between polling for pending txs. */ transactionPollingIntervalMS?: number; - /** - * The maximum number of txs to include in a block. - */ + /** The maximum number of txs to include in a block. */ maxTxsPerBlock?: number; - /** - * The minimum number of txs to include in a block. - */ + /** The minimum number of txs to include in a block. */ minTxsPerBlock?: number; + /** Recipient of block reward. */ + coinbase?: EthAddress; + /** Address to receive fees. */ + feeRecipient?: AztecAddress; } diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index 398c73d1218..f12dff9dfcd 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -1,4 +1,3 @@ -export * from './state_info_provider.js'; export * from './aztec-node.js'; export * from './pxe.js'; export * from './deployed-contract.js'; diff --git a/yarn-project/circuit-types/src/interfaces/state_info_provider.ts b/yarn-project/circuit-types/src/interfaces/state_info_provider.ts deleted file mode 100644 index d653a2284c8..00000000000 --- a/yarn-project/circuit-types/src/interfaces/state_info_provider.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { - ARCHIVE_HEIGHT, - CONTRACT_TREE_HEIGHT, - Fr, - L1_TO_L2_MSG_TREE_HEIGHT, - NOTE_HASH_TREE_HEIGHT, - NULLIFIER_TREE_HEIGHT, - PUBLIC_DATA_TREE_HEIGHT, -} from '@aztec/circuits.js'; - -import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; -import { L2Block } from '../l2_block.js'; -import { MerkleTreeId } from '../merkle_tree_id.js'; -import { SiblingPath } from '../sibling_path/index.js'; -import { NullifierMembershipWitness } from './nullifier_tree.js'; -import { PublicDataWitness } from './public_data_tree.js'; - -/** Helper type for a specific L2 block number or the latest block number */ -type BlockNumber = number | 'latest'; - -/** - * Interface providing methods for retrieving information about content of the state trees. - */ -export interface StateInfoProvider { - /** - * Find the index of the given leaf in the given tree. - * @param blockNumber - The block number at which to get the data or 'latest' for latest data - * @param treeId - The tree to search in. - * @param leafValue - The value to search for - * @returns The index of the given leaf in the given tree or undefined if not found. - */ - findLeafIndex(blockNumber: BlockNumber, treeId: MerkleTreeId, leafValue: Fr): Promise; - - /** - * Returns a sibling path for the given index in the contract tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - The index of the leaf for which the sibling path is required. - * @returns The sibling path for the leaf index. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getContractSiblingPath( - blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; - - /** - * Returns a sibling path for the given index in the nullifier tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - The index of the leaf for which the sibling path is required. - * @returns The sibling path for the leaf index. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getNullifierSiblingPath( - blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; - - /** - * Returns a sibling path for the given index in the note hash tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - The index of the leaf for which the sibling path is required. - * @returns The sibling path for the leaf index. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getNoteHashSiblingPath( - blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; - - /** - * Gets a confirmed/consumed L1 to L2 message for the given message key (throws if not found). - * and its index in the merkle tree - * @param messageKey - The message key. - * @returns The map containing the message and index. - */ - getL1ToL2MessageAndIndex(messageKey: Fr): Promise; - - /** - * Returns a sibling path for a leaf in the committed l1 to l2 data tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - Index of the leaf in the tree. - * @returns The sibling path. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getL1ToL2MessageSiblingPath( - blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; - - /** - * Returns a sibling path for a leaf in the committed historic blocks tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - Index of the leaf in the tree. - * @returns The sibling path. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getArchiveSiblingPath(blockNumber: BlockNumber, leafIndex: bigint): Promise>; - - /** - * Returns a sibling path for a leaf in the committed public data tree. - * @param blockNumber - The block number at which to get the data. - * @param leafIndex - Index of the leaf in the tree. - * @returns The sibling path. - * TODO: https://github.com/AztecProtocol/aztec-packages/issues/3414 - */ - getPublicDataSiblingPath( - blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; - - /** - * Returns a nullifier membership witness for a given nullifier at a given block. - * @param blockNumber - The block number at which to get the data. - * @param nullifier - Nullifier we try to find witness for. - * @returns The nullifier membership witness (if found). - */ - getNullifierMembershipWitness( - blockNumber: BlockNumber, - nullifier: Fr, - ): Promise; - - /** - * Returns a low nullifier membership witness for a given nullifier at a given block. - * @param blockNumber - The block number at which to get the data. - * @param nullifier - Nullifier we try to find the low nullifier witness for. - * @returns The low nullifier membership witness (if found). - * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked - * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier - * we are trying to prove non-inclusion for. - */ - getLowNullifierMembershipWitness( - blockNumber: BlockNumber, - nullifier: Fr, - ): Promise; - - /** - * Returns a public data tree witness for a given leaf slot at a given block. - * @param blockNumber - The block number at which to get the data. - * @param leafSlot - The leaf slot we try to find the witness for. - * @returns The public data witness (if found). - * @remarks The witness can be used to compute the current value of the public data tree leaf. If the low leaf preimage corresponds to an - * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value - * is contained in the leaf preimage. - */ - getPublicDataTreeWitness(blockNumber: BlockNumber, leafSlot: Fr): Promise; - - /** - * Get a block specified by its number. - * @param number - The block number being requested. - * @returns The requested block. - */ - getBlock(number: number): Promise; - - /** - * Fetches the current block number. - * @returns The block number. - */ - getBlockNumber(): Promise; -} diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.ts b/yarn-project/circuit-types/src/l1_to_l2_message.ts index 18e0b12579a..f24312016b5 100644 --- a/yarn-project/circuit-types/src/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/l1_to_l2_message.ts @@ -187,7 +187,7 @@ export class L1Actor { static fromBuffer(buffer: Buffer | BufferReader): L1Actor { const reader = BufferReader.asReader(buffer); - const ethAddr = new EthAddress(reader.readBytes(32)); + const ethAddr = reader.readObject(EthAddress); const chainId = reader.readNumber(); return new L1Actor(ethAddr, chainId); } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 4210e720eaf..cb3c66e27f6 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -573,6 +573,7 @@ export class L2Block { newL2ToL1MsgsBuffer, this.newContracts[i].toBuffer(), this.newContractData[i].contractAddress.toBuffer(), + // TODO(#3938): make portal address 20 bytes here when updating the hashing this.newContractData[i].portalContractAddress.toBuffer32(), encryptedLogsHashKernel0, unencryptedLogsHashKernel0, diff --git a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts index 3b298f06a41..7a1580b9211 100644 --- a/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/l2_block_l2_logs.ts @@ -101,11 +101,13 @@ export class L2BlockL2Logs { * @param blockLogs - Input logs from a set of blocks. * @returns Unrolled logs. */ - public static unrollLogs(blockLogs: L2BlockL2Logs[]): Buffer[] { + public static unrollLogs(blockLogs: (L2BlockL2Logs | undefined)[]): Buffer[] { const logs: Buffer[] = []; for (const blockLog of blockLogs) { - for (const txLog of blockLog.txLogs) { - logs.push(...txLog.unrollLogs()); + if (blockLog) { + for (const txLog of blockLog.txLogs) { + logs.push(...txLog.unrollLogs()); + } } } return logs; diff --git a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts index eb171ebb374..beac122c639 100644 --- a/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts +++ b/yarn-project/circuit-types/src/logs/unencrypted_l2_log.ts @@ -42,12 +42,14 @@ export class UnencryptedL2Log { /** * Serializes log to a human readable string. + * Outputs the log data as ascii if all bytes are valid ascii characters between 32 and 126, or as hex otherwise. * @returns A human readable representation of the log. */ public toHumanReadable(): string { - return `UnencryptedL2Log(contractAddress: ${this.contractAddress.toString()}, selector: ${this.selector.toString()}, data: ${this.data.toString( - 'ascii', - )})`; + const payload = this.data.every(byte => byte >= 32 && byte <= 126) + ? this.data.toString('ascii') + : `0x` + this.data.toString('hex'); + return `UnencryptedL2Log(contractAddress: ${this.contractAddress.toString()}, selector: ${this.selector.toString()}, data: ${payload})`; } /** diff --git a/yarn-project/circuit-types/src/notes/note_filter.ts b/yarn-project/circuit-types/src/notes/note_filter.ts index 9437e8866c1..90570f1f122 100644 --- a/yarn-project/circuit-types/src/notes/note_filter.ts +++ b/yarn-project/circuit-types/src/notes/note_filter.ts @@ -1,6 +1,6 @@ import { AztecAddress, Fr } from '@aztec/circuits.js'; -import { TxHash } from '../index.js'; +import { TxHash } from '../tx/tx_hash.js'; /** * The status of notes to retrieve. diff --git a/yarn-project/circuits.js/fixtures/ContractClassRegisteredEventData.hex b/yarn-project/circuits.js/fixtures/ContractClassRegisteredEventData.hex new file mode 100644 index 00000000000..e6d5bc08ad4 --- /dev/null +++ b/yarn-project/circuits.js/fixtures/ContractClassRegisteredEventData.hex @@ -0,0 +1 @@ +000000006999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f81c9a43d08a1af21c35e4201262a49497a488b0686209370a70f2434af643b4f70000000000000000000000000000000000000000000000000000000000000001072dce903b1a299d6820eeed695480fe9ec46658b1101885816aed6dd86037f015b6f9aad3bac28ee9abb5d28ce58c47a78097c271106637d1d27723c75f91a100000000000000000000000000000000000000000000000000000000000069d200000000032b1eb6a600000021a91f8b08000000000000ffed9d679454c795c7005fcf107b1a248132481a320c33d03d8924a001011239e73c33c4818161c839008aa06c5992654956b0244b969cb32de79c6dd972926dd972d0d9fdb0bb5ff600ecd9fdb275dfabebfe4fcda37b1e5435d550ef9c7bbaeabe57757fb75e55bd005455fd9ee779e55eb0150bb9c36bbbc5e46f5afe262f6d4b69cc2b6992335600209c4505c2595c209c1d0a84b3638170762a10cece05c2d9a54038bb6ae42400b622aff5a69b376ea05c753396788571ee1305c2d9ad4038bb1708e73505c200796d81705e57209c3d0a84b36781705e5f209c371408e78d05c279538170de005c209cb71408e7ad05c2d9ab40387b1708e76d05c2797b8170dea191b33f700096cadf3ef2b7affced277ff9d801f277a0fc1d247f074b5f3bc8f81021654200867ac1fb57dac7055321649890e152472f4c2b855409a9165223a456c808210023858c12325ac81821770a192b649c90f1b22c26089928649290bb844c16320045c85421770bb947c83421d385cc103253c82c21b385cc113257c83c21f385002c10b250c822218b852c11b254c83221cb85ac90be944a5f560a592564b590003542d60a5927a44e48bd900621eb856c10b251c826219b856c11d22864ab90006d429a846c17b24348b3909d425a84ec12b25bc81e217b85ec13b25fc80121000795323f24e4b09023428e2a9cc7841c177242c84921a7849c1672af90334200ce0a3927e4bc90fb84dc2fe401210f0a7948c8c3421e11f23e218f0a79bf9000c7843c2ee409211f10f2a4900f0a794ac8d3429e11f22121cf7aadcfff7342009e17f282900f0b7951c84b425e16f21121af087955c84785bc26e475211f1300f271219f10f249219f12f269219f11f259219f13f279215f10f245215f12f20065215f11f28690af0af99a90af0bf986906f0af996906f0bf98e90ef0af99e0090ef0bf981901f0af991901f0bf989909f0af999909f4b5ff85dcd2f84fc5200d1bd29e45732fc6bf9fb96fcfd8d72ec6f85fc4e867f2f7fff207fdf96bf7f0094bf7f92bf7f96bfefc8dfbfc8dfbfcadf77e5efdfe4efdfe5ef3fe4ef3fe500ef7b42569604e1ce5e664bcbdfe4a56cd50da3e8fd2d57ce52aff5168732e0006348572c5531d071fd2e025d47a92b065d27ce0e74ec5747d07591ba4ea0eb002a759d411797ba2ea093c5e575953aca3f217569f99bbc94ad3ab996f2eca600334ff9eeafbbcc2b01fe5c2375dd4077add47507dd7552770de87a48ddb5a000eb2975d781ee7aa9eb01ba1ba4ae27e86e94baeb417793d4dd00ba9ba5ee4600d0dd22753781ee56a9bb1974bda4ee16d0f596ba5b41779bd4f502dded52d7001b74fc3df136d0954addeda0e3ebea1d524775f50d0fd2487d11e8fa485d3100e8fa4a5d07d0f593918ea0eb0f76583700ea2ceb064a5d17d00d92baaea01b000cbe701ec365382d7f9397b255578ea23c933af314b9529e957af3f4dfd557007999f24d838d24944fb55ebb29b41b93c236585f0ce1d15e66ab8630f7619500104f851c87e1e14a9a04ec4f19f6b91238d210675b1d80cf40bdacd75f2fab00925773bdbcdbcb6c58c7f89a7725d5cbb1c0a0b75ed618a897955775bd5ce4006536ac637c8f7425d5cbe9c0a0b75e8ea877d7f1ac5be47a59ef6536ac637c004f7e25d5cba5c0a0b75e8e4cb9fe32eb16b95e367b990deb183f035e49f572000330e8ad976b53eefe32eb16b95e1ef5321bd6317ee77025d5cb5dc0a0b75e00d61ba897c9caabb95e3ee06536ac63fc8eeb4aaa9727804173bdac72f532eb0016b95e3ee56536ac63fc4ef54aaa970fcb30bdc7fcb57ca7d90b746f495d6f00d0fd46ea6e037ecd757aa4abd359b7c875fa752fb361fde477f857529d7e5e0086a9aefe5ef9de46ba3f485d1fd0bd2d757d41f747a9eb07ba3f495d7fd0fd0059ea0680ee1da91b08babf48dd20d0fd55ea0683ee5da91b02babf495d19e800fe2e754341f70fa92b07dd3fa5ae0274ef49dd30a9a3773afccde50752d7190018d2f23779699bffdd8d7de52da6c4d3101e628e25990016b43354af9d2af200b9cc6bbfcf4381a55cb3cf71c8bf3d2ce5c052a197c5bf9f1ea6374fff9c960029e518073b65e08fd66b96ec9f8679adcb91e36c2b013a6ca3c343f8745fff00626087f3e57812f8585761aeacfc7ad857291bea7ede029b9adba17fade67600ce73e998816d15c3313d4b325c3c16250efbf9fa5102e907838ecf2ff6d9790038cfa9f69c67e2e3f33b3cbf7c95ede553dbcee56ab364b7ca805db50cb80e005519b69b52ec562876e3701e78cb768dc07b3ecdf7d72903f7917e3f5023f300e27b76b6817d5ead81b2af81f28c810dd61743f87fbdcc560b61ee579899da004a55c871184e2a6912b0bfcab0cff8ec908638dba2fef53f8041739d6ff58c00c6f972bc02f4d521e55505e5c5fb87808efb7bbcbe972979c4211fec574d3e0013aa7ee279675d0af8aa43f86af4f25566ab0b35c0c7ba4ac36595eb59f26a00b4abbbed61fe382e09df51f0fe778a32c7f5886598343f7754e2f3006fd9ae006f784dd07b4f5ae9df0757446031f86c983271cf4d799669ce93f218e2b53d003fcc9e80fdd89fe97e9711f35a3f4ba7218e7c8ed5b13a56c7ea581dab637500ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c75a28ac388605c794f171c3002ce0631d8e5fd2fd6edb5f6b40e6c579d3b78b17e0db85de77f495feb74c2e0073fa765d0a0cb8ae3b1ff3d95886eb65192e81fd7cae2e74fe34bfbbcf7afe00d8168e9dc1ef1d9acf9fcf52aeb05cb9762bebf4b7c7ca64372f581783ebd30010c50f1cfb3440d1519d7cb728e3afeeef5951bfad615fa199c51f9758116200476ffb0afa072e7b2ada522fd33f18b86ea4384076792c04f54b7dbcb6fd7200311cf3757922ba7be6ae1317fade3d04ca61b05ebbadc6187ab2fcf99b378e00f156c71dabf3084abdb6630a713cfff7a15fdf026d48735fe57f2bc7be8a5900714b4318fb2fdd7d4dd4b1cb789e755fc74c8c4737511f298faa90f383f74a00bc7f3094978971874394f3c471e473ac8ed5b13a56c7ea581dab6375ac8ed500b13a56c7ea581dab6375ac8ed5b13ad642612516f5db1eae21506e015f1ec60015f8efee79cd1ccedb5fdf14be5d98fc16c6df54fa2bbe16c3318f1765b85600ca7089d7762cc185ce9fe677f759cf1fae3351a694aba9ef69650acb956b3700f856aeb73d66be95737daa52fce0738adf8a5987dff9707c048edf2853749700eb7c609bc1311d1cc6f9b4bacb18e798f3da0efcfd9b6de19ce35db24cf93b00b4de79d7c17ac8bafb75ca83e7cb77f0dad6275c43623ff469076538acffa200fde743f6f396ed3b2bce1f1fa1d757ff7c8e9479f1f91c116277945ebb29b400cb6b75b00dd61743f85c51a63c466582ff2a5f66a676501b721c868728691200b0bfd6b0cf2380230d71b645f5e408d4a9f370fdd67dfd437fb15cfa41b9f0007ebc7731711f55031ca55edb3e05c7443227aeab817df2e5586305d7d5c0710028ec07f627387ef16a1d9ff4345c17c2c6f470dafec0aca9feb762ae5298d5007b051c13f4bc722d33713f7aa13155069fb35a9d3b2e7f751d115c63878f5500ef054abdb6cf3f782ff02af46b6fe7b8ff1face84cf53be8771ae26c0befab00d0efc117f01bd73433b9fe504785836d617dfd8cd2c6d435b998390569f99800cf435acf6bdd3ff3ba4b783f5aa51ca7ff5ea532f45e85fb8711e0031ff38600d25e476ae631703fe69f0abc17280bf18ff77f13dad3b7e1de92cf018e997f0033643f6fd9ee3db9ccc8d7317a7df5cfe79d322f3e9f6342ec8ed56b37857600f9de936db0be18c2bf847bcfb199e0bfca9799a91d8c0e390ec3354a9a04ec001f6dd8e731c0918638dba27af23da8536fc2bda7ee7b2af417cba53f940bef000f7bd7c7c7537de6f680d70added129f4f385f8e677b8ec06b9dfefbbdb6f3003d4abdb6efe0f0dd20f6094bcd3d5b24713e02be6379d7e0f30c954537cf6b00758eba290c57a35dddefa8f0fe8cb7f68c13c7f51c8b804f779b88fa7ea50c00f8f05985f974cf4fc27789ede1c3398a38b787f94ccceb191a81af1cf8385d0047e0d3bdae79d4391315c0c7e93a019fe635d223cf8b1a067cf8ee967f75af00c91c757dc6b0b5d5bb009feef5b5719decf6f085adadde15f85206f82e66fd00e604a48b039fee359de35eeb35a873f1e1ff8c70ba12837cd9ae5bb826ade600e77d7fae15be5fc9552e78df8965441bbe0f31bd8e6e95c2c7f1b03587bb190064892b2cb9ca2f8caf3bf0695eff3885ef83dbc317b626f235c0a7fb9927ea00b337be5be674d7029fee679cb8d7fa7b402e3e7ceee174d7019fdef72d01df0088087c23818fd3f5003edddf77e260b33d7ca3808fd3f504bed106f84645e0001b0d7c9cee7ae0d3fc3ec8e71b1d810fdfa170ba1b80ef4e037c6322f0dd09007c9cee46e0d3fd8e270e36dbc33716f838dd4dc037ce00dfd8087ce3808fd300dd0c7ce30df08d8bc0371ef838dd2dc09736c0373e025f1af838ddadc037c100005f3a02df04e0637d2fe09b68806f4204be89c0c7e97a03df24037c1323f0004d023e4e87ff19799701be4911f8ee023e4e773bf04d36c0775704bec9c0c700e9ee00be2906f82647e09b027c9c0e9f6ba71ae09b12816f2af071ba01c07700b75e3efff96d6a04bebb81659a5e96ea38e4df1e9669c0728f5e969401fffc006f9bd335e74979ccf0da9e1f664fc0fee9505e333497570c6c72be1c473ec7007a75b312cb5485330ec74db5808f75f71864892b2cb465ebebc2f8f05cce3400c0372302df4ce00bab6bb3f4f2f9d7ad9911f86601cb1cad2c55fe77d959110058e600cb6cad2cc1754baf7fc135666e4859b29d04ecc7733e57b36f31b0c900f9721cf91cab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7ea581d00ab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7aa9f9558662a9c7100386ea6057cac9b6d9025aeb0d0966d9c48181f9ecb7906f8e646e09b077c6100756dbe01be7911f8e603dfbc10be0506f8e647e05b007cf343f816eae5f3c7004c2d88c0b71058166b6509fe176f610496c5c0b2482b4b30664aaf7fc198a900252165c97612b01fcff912cdbec5c026e7cb71e473ac8ed5b13a56c7ea581d00ab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13ad642612596050a671c8e005b60011feb161964892b2cb4657bcf1ec687e772a901be2511f896025f585d005b66806f6904be65c0b734846fb95e3eff9bceb2087ccb8165a55e167ffd9600e511585602cb0abd2c2903fef9df7456859425db49c07e3ce7ab34fb16039b009c2fc791cfb15eddacc4b24ce18cc371cb2ce063dd0a832c718585b66cfd5200181f9ecbd506f85645e05b0d7c61756d8d5e3eff1ab33a02df1a6059a79525001837b02602cb3a6059ab9525b8c6e8f52fb8c6d4796dcb92ed24603f9ef33a00cdbec5c026e7cbf13a73767dffeb73f85f1fc2519f47ff91afbdacd30b88d50095ab2b5757aeae5c5db9ba7275e5eacad595ab2b5757aeae5c5db9ba7275e500eacad595ab2b5757aeed672596d50a671c8e5b6d011febd61a64892b2cb465007b771fc687f5aec1005f7d04be06e00b6b17eb0df03544e05b0f7c9c0edbc20006bd7cfe77a2f511f83600cb26ad2cc19afc1b22b06c02968d5a5982ef447a00fd0bbe936c0e294bb69380fd5827376bf62d0636395f8e23df95c85a5740ac00ae0e98617575c0b1ba3ae0585d1d70acae0e385657071cabab038ed5d501c700eaea80637575c0b1ba3ae0585d1d70acae0e385657071cabab038ef572d701006259af70c6e1b8f516f0b16ea34196b8c2425bb67122617c58efb618e0db1c00816f0bf085b58b46037c5b22f03502df9610bead06f81a23f06d053e4e876d00759b5e3e7fccd4d6087cdb8065bb01966d1158b6034b935e969401fffc3153003b42ca92ed24603fd6c91d9a7d8b814dce97e3c85728acc4b255e18cc3715b002de0635d934196b8c2425bb6f613c687e7b2d900df8e087ccdc01756d776ea00e5f3fb9fe6087c3b81659701969d115876014b8b5e969401fffcbe7077485900b29d04ecc773be5bb36f31b0c9f9721cf90a8595589a15ce381cd76c011feb005a0cb2c41516dab2b59f303e3c977b0cf0ed8ec0b707f8c2eada5e037c7b2200f0ed05be3d217cfb0cf0ed8dc0b70ff8385d1cf8f61be0db17816f3ff071ba0012837cc4d24d61e9a6b090dd037aedfad7b5fd5efbcbe500940b96116d71d8008fcc070d94d501858fe307818975dd0cb2c415965ce517c6d71df80e19e03b001881ef10f071ba6b80efb001be4311f80e031fa7bb16f88e18e03b1c81ef0800f071baeb80efa801be2311f88e021fa7eb017cc70cf01d8dc0770cf8385d4f00e03b6e80ef5804bee3c0c7e9ae07be1306f88e47e03b017c9cee06e03b698000ef4404be93c0c7e96e04be5306f84e46e03b057c9cee26e03b6d80ef5404be00d3c0c7e96e06be7b0df09d8ec0772ff071ba5b80ef8c01be7b23f09d013e4e00772bf09d35c0772602df59e0e374bd80ef9c01beb311f8ce011fa7c3e78af3007af9fcfbd37311f8ce03cbfd7a59fcf5cccf4760b91f58eed3cb9232e05f9200f27c40739e94c7835edbf3c3ec09d8ff0094d7839acb2b0636395f8e239f6300bdba5989e59cc21987e3ce59c0c7bafb8045775f403e0f947971de1d84cce9009cb1a9f95ea39afce76b5e27992f33b0ad623866423cc3b5407295c07e3e5700780f83e74ff7bd66cc6b7daf948638db2a015f4e038beefbca98d7fabe286d00995d13f7f951ee534f996349e2bd2fda31f16c18e5d9e68441167c5e423b9a009fd7fd7e6990cc8bf3a6f6bfb9b331dffc7e89cf23f74b83145f8be19801d0002f6d0be9970cb683a4dafe4ac12edbc267ce7b8145f3bb816402388a3c63e70027d5def721bc75b18865bc452ca32c62e96d114b95452c375ac4526111cbb50016b10cb288a5ab452cfd2d6229b688658a452c698b58465bc472d622966a8b00586eb3886598452c3759c432d82296eb2c62895bc4b2d522960e16b12cb3880065aa452c632c62b9dd22961a8b586eb68865b8452c3d2c621962114b89452c00fd2c62e96811cb7a8b58eeb488e50e8b586a2d62b9c52296a4452c3d2d622900b3882561114b378b583a59c4b2c02296be16b198fcd61d9565ac452ca516b1008cb088e5568b585216b1989c4f109565a8452cdd2d62e96c11cb6a8b58665a00c432ce22963e16b18cb488a5d222965e16b1945bc432c022961b2c6219681100cb3516b1c42e334bdc6b3b0e16e7299682eeb80ce3d8c863327c1274452136008a65f838e8f8db19e741cfadf34bda3214419aa3325c1cc2702284f568485a00d3658e76d210675b25c070d402966b2c62196811cb0d16b10cb088a5dc2296005e16b1545ac432d222963e16b18cb38865a6452cab2d62e96c114b778b5886005ac472bd452c298b586eb5886584452ca516b18cb588e594452c7d2d62596000114b278b58ba59c492b088a5cc22969e16b1242d62b9c522965a8b58eeb08800e54e8b58d65bc4d2d122967e16b19458c432c422961e16b10cb788e5668b58006a2c62b9dd22963116b14cb5886599452c1d2c62d96a114bdc2296eb2c6219006c11cb4d16b10cb388e5368b58aa2d62396b11cb688b58d216b14cb188a5d8002296fe16b174b5886590452cd75ac4526111cb8d16b15459c4d2db2296511600b18cb788a58b452c45796239ee65b634c44f805dcdfff9e2af83aef97f6efc003544f9ff6a780d51e6665bc570cc247961e3b11af81f39c7e4ef11381f279400e30cf8908c291c5dc02edbc2ffcbe163291dff975047998e8fe903bef331d300c1f712d00f067ff9bf9386808eff73aa0c74fcdf5d4341c7ff37560e3afe8f00b40ad0f1ffba0d031dff17dd70d0f1ffe62541c7fff597021dffd71f8fa9c300ff07c57910baff3b37e65df83f519b808fffd3733be8385c053a4e530d3afe009fd71ad035ca702de8b6c8f008d06d96e191a0e3ffd21e053afedfefd1a0db0020c36340d720c37782ae5e86c782ae4e86c7816e9d0c8f07dd5a194e836e8d000c4f01dd2a19e6f77b747e57283a3abfcb95fc9297b6f9e797ed70be1c5f0e007c2b657805e8383c1398972a3a625e628079a9c2ccf125c0c7fc4b41c7e10500c0bc58d111f32203cc8b15668e2f023ee65f0c3a0e2f03e6858a8e98e71b60005ea830737c3ef031ff42d071783530cf5374c43cd700f33c8599e373818ff900e7818ec3eb81798ea223e6d90698e728cc1c9f0d7ccc3f07741cde0accb314001d31cf30c03c4b61e6f80ce063fe59a0e3f059c37c3b14be1d0a9f29bb2b1500bb2bf36477b96277799eec2e51ec2ec993dd458add4579b23b5fb13b3f4f7600e72a76e7e6c9ee6cc5eeec3cd9bddaeaf3e5ea37aeb6fa7cb9fa8dcbd58edc0075303f76dd75303f76afb6eb607bdaef34bd76fdffce9ce1b5de624a3c0de10069c0325d731918f0cf7fdd760ff0cf50fc48c0fe23e0db3d9a7d8b814dce9700e3c85728ac71d01d041def3f00babb65783fe826cbf03ed0dd25c37b4137490086f7806ea20cef06dd0419de05ba7332bc0674e7657815e8ee93e195a0e3ff00335c013afedfc9e5a0e3ff5c5c0aba87647809e81e96e1c5a07b44861781ee007d32bc10748fcaf07cd0bd5f86e781ee31199e0bbac765780ee89e90e1d9a000fb800ccf00dd93323c1d741f94e123a07b4a865b40f7b40cef04dd3332dc0c00ba0fc9f00ed03d2bc3db41f79c0c3781ee7919de06ba1764b811741f96e12d00a07b51863783ee2519de04ba97657823e83e22c31b40f78a0c3780ee5519ae0007dd4765b80e74afc9f03ad0bd2ec36b41f731199e053afec6360d743c0e0400db2a8f9bbc1b743cb67f32e878ced75da0e379c99340c7df1927828ec7594c00001d8f4b3c073a1e3b7f1e740919be0f743ce7eb7ed0f1b7ae0740c7eb783c00083a1edbf010e8785ce2c3a0e3f1ea8f808ee731bd0f743ceff751d0f13a1900ef071d8f1d780c743ceeef71d0f178f02740c7f3843e003a9e57fb24e878ed00870f828ebfcd3f053a1e57f734e878bcf533a0e379381f025da90c3f0b3afe000ef71ce8facaf0f3a0eb27c32f808ec7037d1874bcb6c78ba0e375505e02dd0020197e1974fc9def23a0e3ef7caf80ae4c865f05dd5019fe28e8ca65f835d000f177bed741c7dff9b82d523b30f15d9b6cf11c59deb2dd97e1b7eee37a59fc00efd22780210d360681dda39acb806c1d53ec3207db4a4039f1b1d4bff0f50900ff47f3908172e17b1ffe5ecf0c6c0bbf5957cace90fb30d6d37626c487c3ca007171081f86e3d8d649c88fefbf8a200d7e97df0fe1234a1a2ad3d3ca71f89d009ced5099f27d595afe262f654b05f7eb7b819d6dee0136b6bf173876e9e49000758fef2f395faeeb788fc93a3e96aeb3fc3fb3546685f83fd37afbb2cae4a500f46527b5b204cf989afbeaa4fe3eb7ce1f12720ccae494523609d87f1ccaeb0098e6f2c2be9ff3e5f8317376fd211d4773f87f3484e3681efd3f6acc6e8dff0018712487ff474238348f73cbeaff11637647f8c3810ee7f0ff700887e6f16c0059fd3f6ccc6ecabf0e1ecae1ffa1100ecdf73859fd3f64ccee28bffd1fcce100ffc1108e8379f4ffa031bb35fef93f90c3ff03211c07f2e8ff016376d7fbfe00efcfe1fffe108efd79f47fbf31bb35fed0c77d39fcdf17c2b12f8ffeef336600b7d2f77f6f0efff78670eccda3ff7bcdd9f55f05eec9e1ff9e100eadcf633900fcdf63cc6e957fffb33b87ffbb433876e7d17fe46b2febf1cbcc6ac0aedf560077e5f07f5708878967f60bf98f7ced6535fd7e2117ab7ebb0d7ebfd292c3ff0096108e963cfadf62cc6eca9f8eb03387ff3b433876e6d1ff9dc6ecd6f89f93009a73f8df1cc2d19c47ff9b8dd9adf1a78fecc8e1ff8e108e1d79f47f8731bb00297f0ad1f61cfe6f0fe1d89e47ffb71bb35be59fffa61cfe37857098986f750021ff9b8cd9adf5fddf96c3ff6d211cdbf2e8ff366376ebfc7b95c61cfe3786007034e6d17fe46b2febb1cbccaadfee48ff1dc0961cfe6f09e1d89247ff91af00bdac072e33ab7ebbebfda99f9b73f8bf398463731efddf6cccee3affbaba290087ff9b423836e5d1ff4dc6ecaef5a7cd6dcce1ffc6108e8d79f47fa331bbb500fe7565430eff3784706cc8a3ff1b8cd91de94fe96ec8e17f430847431efd6f003066b7daf7bf3e87fff5211cf579f4bf1eeceafec61f83fc792ccc40a50c8a00e1987f57c6c284951da7a7710aa7437ca8d3ea43309e67dd057ca8031ff89800ff021f3a835e178f011ffd71053ca694c6aadc1be21fefffef78e6b8ff91e100389c8333904fe792b6fb79cb36d683cb8c7c5da5d7d724ce4de2f3b92ac4ee000abd765bcd898a49611bac2f46361e10ebb55ea381cb9799714d093c0ec3f5004a9a04ec5f63d8e755c0918638dba27af27f50a7b8cee8ef8f827abec66b5b002e03a15c783f8e7dd2dddea85cd67aadcb45ed5388e59cc249c5c47514c78900ad31c0b74ee1e3f81ae063dd09e0633fb03f990363df783c2eaec9c3636fcb00209f618a8eb2186ec04fb6c3f9721cd7e92997e161f9e5ab6c2f5f85c2472c0029cd6515079bbc65ebc353c092d4cc62c03f1fb112f8872b7e24607f29f85600a9d9b718d8e47c398e6b3de93ebf31c89faf8b7d9532288663ca643fdd5d6100c3b2e3f4b8b670a5e1b2abf05a975d4588dd1a8365c7f9723f5763d86e956200b75cb14bed16eb136dd9da6d15f0566be6a53c6bf5e6e9dfcff19a605c6fd9004639f832d240d98f80f28c810dd617437802dccf8dcc04ff75edc3b5ce6a42008ec3704a499380fd35867dae058e34c4d9165def6be11e4e739df7cf778dc200c0f172d0d78694570d9417ef1f063abe27a9045d9992471cf2c16bbfe67a9d00cae6279e77d655015f6d08df08bd7c95d9eac208e0635d35b098e8075516be00f6603fd857293faaab6f015767bd5cd5389f92b76c7d6f67f8eda4b98c681e0026cf6bac5bdbd83867d7bac64d7553766dab6bd9d4b42d06741da174682b0600c22208a39e8fc599a11d41c733433b81ae48f11a67a976815fb5c4b4561b8200e8e705b7741cefef65ba748a0f50e20395f82025fd71257e52899f56e2679400f839257e9f127f40893fa4c41f51e28f2af1c794f8134afc4925fe94127f4600893fabc45f50e22f29f15794f86b4afce34afc534afcb34afc0b4afccb4afc00ab4afc1b5eebf8b795f8f794f80f95f84f94f8cf95f86f94f81f94f81f95f8009f95f85f94f8bb324ec21befa306438d8f1a1b352e6a4cd468a8b9f3b46aea008669da34ddaad3b4689a064dd39ea93ba069cd348d99a62dd334659a964cd3009069da314d33a669c5348d98a60dd334e13b80e107f2b7d40ba601f7f582b60044ed87da0cb5136a1b7459a5db61ba1cd1ed0e5da6e9b69c2ebdf4a840cf5e007479a5cb2e5dc6e85241dd3675d37429a15b0b1afb4fcbb7d272adb43c2b2d00c74acbafd272ab692f985e3ed10ba6a3d334f5c95eb0c4ea542f98de4ed3de00a779c1b20533bc6089529a324fcb1dd03208b43c022d9b40cb29d052a0b4d400022dc1404b33d0920db494032db749cb3cd0ab2b7a4d47afb26839cb355ef000ba639d17bcbea1d735f43a9fbe7f6df0824f3bf4798b3ef1d1674efa2c4dcb0033d250021a4e41434a68580d0d2da2e15534c48c86d9d1b0481ac64a430e690038330de9a6cfc434b49fa637d0140f9ae672d40b3ef553bf43af62a8bfa1d700e5d4cfd0ab5cea5f68b945ea57687a3df527347d9efa119a1e4ffd074d7fa7007e83a6b7537f41d3d7a99fa0e9e9d43fd0f473ea17687a39f507347d9cfa01009a1efeac174cff7ede0bda3e4de77ed10bdafdcb5e301d9bdafcab5e30bd9a00da3b4d9fa6e9d2d4d63f21e4935ed0ce3f2de4335ed0c63f27e4f35ed0bebf0028e44b5ed0b6bf22e40d2f68d75f13f2752f68d3df14f22d2f68cfdf11f25d002f68cbdff782ba4aedf847427eec056df8a7427ee605edf717427e29e44d2100bf12f26b2fb835a0b6fc5b21bf13f27b2f68cb6f7b411bfe9317b4dd77bca000cdfed50bdaeadf84fc5dc83f84fc53c87b5e6629839897d9be26237d647c6d004b4bc3d6ed2da52d4da55b7735b66cdadeb8af74cfa6968da54dbb1b9ad7370036edc1c42df2f2c9eb034c686e5ebbaf74d3b6fa86bda54dbb5a4a9bd697ae006bdab5ad7e27267aaae8122c3e2713f76e9b786d7dfd85d37d5aa6e31514ee00c9cef8b98b71ec2b17936862d78b48948a5f44a27fbb9844ff7931898694b4003391f7fff9ff659b0d070200122ffb5900000023ff1f8b08000000000000ff00ed9d077c1c35f6c7b5dec44ed64ee8900638092440daae7bfaa6170204482300dd8eedf438c54e2f4eeff4bbe30a9d038eff1dd73b5c3fae72bdf7de7b2fdc00dd5f9ad1637f9627bb9e44da6812cde7f33e2bbd19e97d9f46a3d18e349ac20018638399bfc5b95ccdda6f31f99b96bfc933db521af34a9ae48c4584b32022009cf18870768a0867e78870164684b328229c5d22c2d95523a7602b606d37dd00bc0903e5aa9bb19845e3dc974484b35b4438bb4784f38288705e1811ce8b2200c2797144382f8908e7a511e1bc2c229c974784f38a8870f6880867cf8870f6008a0867ef8870f68908e79511e1bc4a23a760539f33eae6bdda40b9ea662c8d000063df0830f68b0063ff08305e1301c66b23c03820028c0323c0785d0418af008f00e30d11601c1401c6c111601c1201c6a111601c1601c66404185311602c008b00637904182b22c0581901c6aa0830564780b126028cc323c03822028c230023c0382a028ca335325ec332db18f93b56e11d277fc7cbdf09f277a2fc9d24007f274b5f3bc9f8142e53b94ce3325deea342b991cb0c2e3771b999cb2d5c660072b995cb6d5c6ee7328bcb6c2e73b8cce5328fcb1d5ce67359c0652197455c00167359c26529975a2e755c9671a9e7d2c0a591cb722e2bb8ace4b28acb6a2e006bb8ace5b28e4b1397f55c3670d9c8651397662e2d5c3673d9c2652b976d5c00b64b5f4aa52f3bb8ece4b28bcb6e2e7bb8b472d9cb651f97fd5c0e7039c8e5001097c35c8e7039cae51897e35c4e7039c9e54e2e7771b99bcb3d5ceee5721f0097fbb9bc82cb2bb9bc8acb035c5ecde5354a99bf96cbebb83cc8e52185f361002e8f707994cb635c1ee7f20497d7737992cb535c9ee6f2062ecf70f93f2e6f00e4f2262ecf72793397b770792b97b771793b9777707927977771793797f77000792f97f771793f97e7b83ccfe503acedf9ff20970f71f930978f70f928978f0071f9389717b87c82cb27b97c8acba7b97c86cb67b9bcc8e5735c3ecfe50b5c00bec8e54b5cbecce52b5cbecae56b5cbecee51b5cbec9e55b5cbecde53b5cbe00cbe57b5cbecfe5075c7ec8e5475c7ecce5275c7ecae5675c7ecee5175c7ec900e5575c7ecde5375c7ecbe577d2179aebf47b2e7f50747fe4f22719feb3fcfd008bfcfdab72ecdfb8fc5d86ff217fff297fff257fff2d7f5f92bfff91bfff9500bfff93bfd4d8c4e46f81fc8dcbdf4ef2b7b3fc2de4bf2f14fbe12296d9d2f2003779265b65b2bab367d4cf6b0c6bbb25a00ce818a18b932ba0a3fa5d00bace005217075d2165073af2ab33e8ba485d21e8ba4a5d11e81252d70574b2b8585700a913f997485d5afe26cf64ab48d68a3cbbe9cc53ce9deb2ef32a017f2e90ba006ea0bb50eaba83ee22a9bb0074174bdd85a0bb44ea2e02dda5527731e82e9300ba4b4077b9d45d0aba2ba4ee32d0f590bacb41d753eaae005d2fa9eb01bade0052d713747da4ae17e8ae94badea0bb4aeafa808ec6c9ae045da9d45d0575a400afd4a5e56ff24cb68a54a3c8b39fce3ce53ce00fb08c1f63247f01e8c64a5d001c7469a9eb04ba7132d21974e3a5ae107413a08c483751eaba806e92d4750500dd642873ca6398d672aea816792675e6c973157996e9cdd31bb32d6799f24d00838d24944f855ebb29b41b934236481f87f04896d92a204ced6a19c45301c70061789892a604f6a70cfb5c061c6988932d5135b1dc35d7cb3afdf5b23c793e00d7cb692cb3611da3fbf0b9542fc70083de7a596da05e969dd7f5722ecb6c5800c7a8df762ed5cb19c0a0b75e0eaf73f7f1ac5be87ad9c0321bd631fa9f702e00d5cbf9c0a0b95e36baf632eb16ba5e6e62990deb18fd2f3d97eae50a60d05b002feb1a5dff32eb16ba5eee65990deb183d073997eae56660d05b2f1b0cd4cb0064d9f95c2fef62990deb183d773b97eae50160d05b2f1b53ae5e66dd42d7cb00075966c33a46cf79cfa57a79af0c8be7987f96cf347b83ee2f52d707747f9500ba2b815f739dae72753aeb16ba4e3fcb321bd64f1a573897eaf4e3322ceaea003f645d2d05dd3fa5ae2fe8fe2575fd40f76fa9eb0fba97a4ee1ad0fd47eaae0005dd7fa56e00e8fe27750341478314d7812e2675d783ae40ea6e005d5cea060081ae93d40d065d67a91b02ba42a91b2a75e2990e8db97c4aea8a209fb4fc4d009ed9e68d05122f6d31259e86f060732cc91260413b43f5da294f40d977c4e700a1c0a2b55de55b02f2ef08cb3060d1dc1e7bfd9694de3cbd733a4429c704d8001902fe68be1778ed538ab52d478a635b9952ca3601fb91af5c2f5f59b6f6b3001cf882ee5fbaef9bc2e7fe4ad988e6e7eb6053f375e8ddabe93aa7f5b18881006cc5e1989dc519ae6f0397ee365170d17d87f2a5b8c1f6ef7cb3ebd5b96b14003be2dcfe046ceaad73a946ac73a27fb8071882eadc44a873bf90ba62d83f080074941eefebb6b473828fdab7547ef9ca3aca9754f80cdc8f5238f790f2757600f5df4f307f71edd0f54276e2b0ffd30599e35e02a6417a99cac2f6fb06192b009fb264d87e7719b0e8ae2326cebf81fe9257a72a02ce4fd0ffde7228afb3f100bfd7b13a56c7ea581dab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a5600c7ea58a3c48a63f938c72568acfc6cf191cee4d886f099e616e158f9c958c600a6de67f465de583995b918b72c0506b21587631e8e65b8ee91611cb7c4314a0075dcd2c03c17effce13c9734c4c95631f0e39c1bcdf30e52589694efb96bb7006c9989f78ac4bbb0e2fd7baa4f49c50f9c4b3350d1893af96241c65fdde3590061c7d60c8ebfb699d38676f48e8df9ed03b545a2684b59a67d3070df48514000d8ad94798976a92f6bdf2ec7e19867e489e8ceccdd274e35de5d01e550a9d7006e12e7fb3259fe746d90ad0484e95891ae0acaaf14caaf12ca8f8e791bb4eb00b3e11ad23d6703e7863060c52d0d611c9fd67b4efdb1f2b2102c789e358f4100a70cd4d9a489fa28f2a862edcf0ff695687f25945795e6f252af8b34c491cf00b13a56c7ea581dab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7ea0058a3c28aef951367028e4b59c097877905deb37b5a7383f21663171360ecc200e458188da90c507c8dc3317b0b325c5364b898b59f4b70aaf3a7f9d97dd6f30047b68ac1171cef30319e56aeb09cbb76fdb172bdd76366ac9cea5395e2079d00531c2b261d8ef3e15a40387fa35cd19dadf381d74c39e8288cefd3ea2e63c100572df3a2759f68fc9b6cc5e19825b24c691cba5a338f89765de45123f3eac400dad7a738ecaf8736ad518683da2fb1bf25603f6dd9c659a9cc84af23f4faea009d4ffa3e009dcf11017647e9b59b42bbb48e17d9207d1cc2cd0599f218950900be5cbec42cae83e101c761b842495302fb871bf6790470a4214eb6443d59090075aa05eedfbaef7fe82f96cbb5502eb41ffb2e26fa5135c051cadab7293827009238c575447514dbe4e106f8aa812f0df1e1c0473a9c87427e607b82f317cf00d7f94987e1be1034a787d20e00664df5bf0d7395c2acf615704ed009e55e6600a23f7aaa395506ff67b5397754fe34a78a6c2558fbff7c6a5fa094b5ffff83007d81fba15d7b01fa5a542fb1ff5fa9e84cb53be8771ae2640bfb5ae877e52900fcc6759cf4f6757c5ee2eaac70902dacaf0f29d7580d30a7817918a4a5631e0085b48cb56d9f69ee29f647ab94e3f4f755ca02fb2ad43e8c001fe898a794eb0075a4661e03fd31afba635fa02cc03fdaff46b89e9e85be259d8372c8e7f98000fdb465eb7b5299095fc7e8f5d53b9ff4ed533a9f6302eca6f5da4da15dea7b0052dea48f43f8b982e0b2a1f22566711d8c0e380ec3354a9a12d83fdab0cf63001426f57c8a7af256a853cf43df53779f0afdc5721900e542fb839ef5d1f1a2003ed3f580f70addd725fe3fa17c299eed7f04deebf4f7f7dabfaf53cada3f8300c36783f81e0d3e1bd4bc065812df471804365f3467d32b0bfa7618e5db4d6100381feddab296313e772b00be2106f80687e01b027c942e0e7cbadf4f3add750091f13f7027e0d3fd0ed9e9ae955c02e93a039feef5931360b3237c49e0a3740085c067e2bda86408be14f0e1dac3f4abf99d93d4e9be7382f7df2ec0a7fb9e0016f63d94a0359c5ffeb634d3ff8c1ec7023ac287e3a6784f263eddcf11c23e005fc67111fc4f678a2fdb7dcbe0738e327caed09172c17e279691d8829e879800fecf4ff952bc1a9848d7cd204b4261c9557e417cdd81afc6005f7508be1ae000a37417009feeff3c61ff7be3b3654a7721f0e9fe8f93606dc70372f1e1ff1e004a7711f0e97ddee2f38d08c13712f828ddc5c0a77b7c27c1da7e6b3b17df2800e0a3749700df68037ca342f08d063e4a7729f0697e1ee4f18d0ec187cf502800dd65c037d600df98107c63818fd25d0e7c69037c6343f0a5818fd25d017ce3000cf0a543f08d033ed2f700bef106f8c685e01b0f7c94ae27f04d30c0373e0400df04e0a374bd806fa201be0921f826021fa5eb0d7c930cf04d0cc13709f828005d1fe09b6c806f5208bec9c047e9f0db74530cf04d0ec13705f828dd55c03700d500df94107c53818fd25d0d7cd30cf04d0dc1370df8281dfeaf9d6e806f5a0008bee9c047e90602df8d7af9bcff6fd343f0dd082c37e965a94840fe1d61b900095866e8654919f0cf1bdbbc59739e228f5b58fbf343ec25b0ff6628af5b340097570c6c52be14473ec77a7eb30a96e90a67028e9b6e011fe966186449282c0062cbd6d605f1e1b99c6980ef96107c33812fa8aeddaa97cfbb6fcd0cc1772b00b0dcae95a5dc1b97bd3504cbedc0729b5616ffbea5d73fff1e332ba02cc94e0009ecc7733e4bb36f31b049f9521cf91cab6375ac8ed5b13a56c7ea581dab630075ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7ea581dab6375ac8ed5b1003a56c7aa9f55b0cc54381370dc4c0bf848779b419684c222b66cf34482f8f0005cce36c0372b04df6ce00baa6b730cf0cd0ec13707f86607f0cd35c037270400df5ce09b13c0374f2f9f37676a6e08be79c0325f2b8bff5dbc792158e603cb001d5a59fc39537afdf3e74c2d08284bb25302fbf19c2fd0ec5b0c6c52be1447003ec7ea581dab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7ea581d00ab638d0aab6099ab7026e0b8b916f091ee0e832c0985456cd99eb307f1e1b9005c68806f4108be85c01754d71619e05b18826f11f02d0ce05bac97cf1bd3590014826f31b02cd5cbe2addfb23804cb526059a2972565c03f6f4ca796b52f4b00b25302fbf19cd76af62d0636295f8a239f633dbf5905cb22853301c72db280008f744b0cb2241416b1656b9782f8f05cd619e0ab0dc157077c41756d995e3e00ef1e5317826f19b0346865f1e70d2c0bc1d2002cf55a59fc7b8c5efffc7b4c00634059929d12d88fe7bc51b36f31b049f952bcd19c5dcfffe539fc5f1ec0b1003c8ffe235f47596f8e10ab2b5757aeae5c5db9ba7275e5eacad595ab2b575700aeae5c5db9ba7275e5eacad595ab2b5757aeae5c3bce2a58ea14ce041c576700011fe9ea0db2241416b1657b761fc487f56e8501bee521f856005fd075b1d20000df8a107c2b818fd2e1b5b04a2f9f374eb43204df2a6059a395c55f937f5500089635c0b25a2b8b3f4ea4d73f7f9c646d4059929d12d88f7572ad66df62600093f2a538f29d8bac8d11627575c00cabab038ed5d501c7eaea80637575c0b100ba3ae0585d1d70acae0e385657071cabab038ed5d501c7eaea80637575c0b100ba3ae0585d1d70ac67bb0e0896950a67028e5b69011fe9561b6449282c62cb00364f24880febdd3a037c6b43f0ad03bea0eba2c900dfba107c4dc0b72e806f00bd01bea6107ceb818fd2e1b5ba412f9f37676a7d08be0dc0b2c900cb86102c009b8065a35e969401ffbc3953cd016549764a603fd6c966cdbec5c026e54b7100e48b0aab6059af7026e0b8f516f0916ea3419684c222b66cd74f101f9ecb1600037ccd21f85a802fa8ae6dd6cbe7b53f2d21f83603cb56032c9b43b06c0596002d7a595206fcf3dac26d016549764a603f9ef36d9a7d8b814dca97e2c817150056c1d2a27026e0b8160bf848b7c5204b4261115bb6eb27880fcfe576037cdb0042f06d07bea0bab6c300dff6107c3b806f7b00df4e037c3b42f0ed043e4a970000be5d06f87686e0db057c94aed8209f60e9a6b074535884dddd7aed7af7b5005dace3e5b21bca05cb486c09d88fcc7b0c94d56e858fe27b808974dd0cb2240014965ce517c4d71df85a0df0ed09c1d70a7c94ee02e0db6b80af3504df5ee000a3741702df3e037c7b43f0ed033e4a7711f0ed37c0b72f04df7ee0a374170300df01037cfb43f01d003e4a7709f01d34c0772004df41e0a3749702df21037c000743f01d023e4a7719f01d36c0772804df61e0a3749703df11037c8743f01d00013e4a7705f01d35c0772404df51e0a3743d80ef9801bea321f88e011fa5eb00097cc70df01d0bc1771cf8285d2fe03b6180ef7808be13c047e97a03df4903007c2742f09d043e4a87ff2beed4cbe7f54f4f86e0bb1358eed6cbe2ad677e67000896bb81e52ebd2c2903fe25459ef768ce53e4712f6b7f7e88bd04f6df03e50075afe6f28a814dca97e2c8e758cf6f56c17252e14cc071272de023dd5dc0a200bb2d103e5f27f3a2bc3b71195194b1a9b9af5121fca77b5ea1cc9718c8561c008e599fc8708d915cc5b09fce15f661f0fce9ee6bc658dbbe521ae264ab187c00390a2cbafb9531d6b65f94b6ccae897e7e987eea11732c49ecfba21d13ff0d00c3fcb739649005ff2fa11dcdffd7bd76e97a9917e52daeff5945c67cf3da25003a8fd42e5daff81a87636641bb342fa05d32781d24d5ebaf14ec922dfccf79000c58343f1b489600470133767e521d7d1e42db788b584659c45265114bd22200963e16b10cb088e5728b582eb488a5ab452c718b58a659c432c12296d116b1009cb088a5da229694452c832c62b9d222962b2c62596f11cb4516b1242c62590064114b278b58a65bc432c622961a8b58ca2c62196c11cb5516b1f4b088e562008b58565ac4526c11cb7516b15c6b114b678b58c65ac432dc2296728b58865800c472b5452c3d2d62b9c42296128b58ba59c472bd452c8516b1ccb588e5068b00584c8e758765495bc432c22296fe16b15458c432d42296528b587a59c462f2003d8bb02cdd2d62a9b388a5c822969916b15c6311cb388b58465ac45269114b005f8b58fa59c432cc2296de16b15c6611cb0516b10cb488a58b452cb1b3cc920060ede72ae3bba4a5a0a379be387f95debd3d0cba82001b34ffe920e868ac9500f228e4f25c717b86024843ef22c703180e05b0ee0f486bbaccd14e1ae264ab001818f65bc0d2c522968116b15c6011cb6516b1f4b6886598452cfd2c62e96b00114ba5452c232d62196711cb3516b1ccb488a5c822963a8b58ba5bc472a945002cbd2c6229b58865a8452c1516b1f4b7886584452c698b588e58c47283452c00732d6229b488e57a8b58ba59c4526211cb2516b1f4b488e56a8b588658c452006e11cb708b58c65ac4d2d922966b2d62b9ce2296628b58565ac472b1452c3d002c62b9ca2296c116b19459c4526311cb188b58a65bc4d2c922964516b1242c0062b9c82296f516b15c6111cb9516b10cb2882565114bb5452c272c62196d1100cb048b58a659c412b788a5ab452c175ac472b9452c032c62e963114bd22296002a8b584659c432de2296823cb1e03764d2103f0476f7e9b5eb7d4f60afde3c00bdb5785b655e85325fe2265b713866acbc99d0bc11d28b8de6efee83f371480039ae88e9ff2697f0a11f6b7b3efa39bb67cdaee63aaae59b66fb80cfc437eb00f686e0db639005bf938676347fe7d05b379ce63050dee2d9d4ecae199b7abf0067906a14657a5ce6456d1531047dcfa006d60dbf4372e1bae1ad2cb31d031f00a8cd3a0e79d2fe45d0fee1b707e83fbcd0d17ae4834147734f8680eeb00c0f00051ddd4786818edad524e8e8fe96021dd5f132d0515d28071dd58b0ad0d13900a439bef87d4f7c8f4ff7775863aced7744d310df017cf4fd4bfc762885ab40004769aa4147df6bad011d7d637638e8e8bbb8234047dff01d093afaeef028d000d1778747838ebee93d0674f41df2b1a0a36fa6a74147df791f07ba26191e0f00ba75323c01746b65781ae8d6c8303dcb16e77795a213e77785c2923cb3cd3b00bf6487f2a5f80ae05b2dc3ab4047e199c0bc5cd109e64603cccb15668a3702001ff12f071d85e7027383a213ccf506981b14668ad7031ff137808ec28b80790099a213ccb506989729cc14af053ee25f063a0ad701f3524527989718605eaa0030537c09f011ff52d0517825302f56748279a101e6c50a33c517021ff12f06001d85d703f302452798e71b605ea030537c3ef011ff02d051f88461be5d0adf002e85cf94ddd58addd579b2bb42b1bb224f761b15bb8d79b25bafd8adcf93dd005ac56e6d9eec2e51ec2ec993dd858add8579b27bbed5e7b3d56e9c6ff5f96c00b51b67eb3a72f7c1fcd875f7c1fcd83ddfee831db97ee7e9b5eb7d877a3e6b00bb657b663a0f58eed05c0606fcf3c66ae668ce53e4311bca64be523625b07f000e94d76ccde515039b942fc5912f2aac09d01d031ded3f0aba59328c6be7dc002ec38741779b0ce33a39b7caf001d0dd22c3fb4147df7fdf07ba9b64782de80066c8f01ad0dd28c3ab4137558657816e8a0caf00dd64195e0eba4932dc08ba008932dc003afa0e703de8e87bcfcb4047df58ae051d7d0f7929e8e8bbd54b400047df6c5e0cbafb647821e8ee97e1f9a07b850cdf01ba57caf01cd0bd4a86f70082ee0119de03ba57cbf06ed0bd46867781eeb532bc1374af93e11da07b508600b783ee2119de06ba8765782be81e91e12da07b54863783ee31196e01dde33200dc0cba27647813e85e2fc31b41f7a40c6f00dd5332dc04baa765781de8de2000c30b405720c3f340179761bc56690ef42cd0d13b43b783ae50866f035d910c00df0a3a5a37e916d0d19ca99b4147738c6f021dbd07330374f47ee48da0a3f70037a7828ec6d0a7808ed62a9a0c3a9a3335097434c77822e8e8dd13fc4e37bd001f89df5ea77516ee021dad4b7437e8687ed43da0a339bcf7828ede33b90f7400f42ee4fda0eb25c3af001dad41f44ad0d1fca357818ee6eb3e003a7aa7e4d500a0a3f71e5f03ba52197e2de8facaf0eb404763d90f82aebf0c3f043a5a63e50061d0d17b628f808ee6743d0aba8132fc18e8e8bdaec74147ef1e3f01ba1b6400f8f5a01b24c34f828ec61d9f021d8d3b3e0d3a1a77a46b515c07fac76dfdf100f1e3aced96adaf47f6058bdeefa9fb63c8c780210d366e00bb87b5daf5fb21004714bbc441b64a58fb6f4be398702bf0ed37502ed4dfa0b17575bd84381c3300493686d486915e6c7d037c50e70625207c008e235b7b213fbaef16409afdb0007f37840f2a69700ec86eb0b34bb1a37d6c3be5f7d777023bd9dc016c647f2700706cd3c921eb1ef52b285faaebd8b7201d1dabcee7d03d8f4ed83cc2da6ed900da059c5b77502f8b370fee1030a4c1067eb743ef75e79f9b038a5de2205b2500504e78add0b57014f85a0d940b5d4bd42e1003d98ac331b54abb407ab11d0f00f0419dab9480f05e38ae55860f437e743d17409a56d88fcf35f6296944991e00558ec33925644794295d0f69f99b3c934db60b3b809d6c6e0736b2bf0338b600eae490758fae7fca97ea3afebf201d1d2bda8559459932a3f38afdcea38a4e001c7ec400ff51d6969fe278efa1fb2c5e277adbb2b2e499b465bafb1a06daea00a4fe36b7dc9b7a7500cae488523625b0ff2094d701cde5856d3fe54bf103c600ec367aedc0fe1cfeef0fe030710f3a95fffb8dd9adf0a629eecbe1ffbe008e007d79f47f9f39bbde63b1bd39fcdf1bc0a17b7e7536fff71ab35be93d3e6ccd00e17f6b00476b1efd6f3566b7ca9b8eba2787ff7b023874cf19cfe6bfb9b9ea00296f5af1ee1cfeef0ee0d03c973dabffbb8dd9adf0a62defcae1ffae008e5d0079f47f9731bb75def4f39d39fcdf19c0b1338ffeef3466b7ae4ee4b12387ff003b02384cccc13f95ff3b8cd96df0a6e86fcfe1fff6000eadffc772f8bfdd9800dd2aefd58d6d39fcdf16c061e2f9d0a9fcdf66cc6ebdd7ffd99ac3ffad011c0026fe079fcaffadc6ec56d78a3cb6e4f07f4b00c7963cfabfc598dd06affddb009cc3ffcd011c9bf3e8ff6663762bbdf3df92c3ff96008e963cfadf62ceae7700ff6fcee17f730047731efd6f36667799f7fc63530eff3705706ccaa3ff9b8c00d9adf3daff8d39fcdf18c0b1512b4776ff371ab35be3f57f36e4f07f4300c700863cfabfc198dd5aef95d4a61cfe37057034e5d17fe4eb28eb8eb3ccaadf6e00b9f7ac665d0effd70570accba3ffeb8cd9adf4faea6b73f8bf3680636d1efd00275bfaedd67bcf2a689ea1d882fca7fdc8b1462b4776ffd718b35be3ddab5600e7f07f7500c7ea3cfa8f7c1d656d3dcbacfaed5679fdea5539fc5f15c0b12a008ffeaf3266b7deeb57acc8e1ff8a000e13effe9fcaff15c6ecd679fdeae53900fc5f1ec0b13c8ffe2f3766b7cc3bff8d39fc6f0ce030b18ec2a9fc6f3466b700d61b576cc8e17f430047431efd6f00bbbae722e05a108532dfeb943288c331007de424e6ee0a1b961da5c7f56dd007cdeb5954e0da10aa0ff5e0031dd30f7c002802bd2e1e033e7a7d4a7a0f42cca93916e01fed1f589c39ee7a194ec03938000ef9d404eca72ddb9c142a33e1abe6753392b806059dcf2501764dae7d1193004236481f8770354de8676ddfc7a3f2c5353e96061c87e106254d09ec5f6ad800e753bdc348b6443d190c758aea8c81b94329f417cbe53a2817da8f73b44cac009153cbda968bdaa60896930a27ae8783f3d9961ae03bd57a384b818f748780008ffcc0f66444518675a856567fbe38ad5146d733bd1741b6e270cc54e51e43007ab1f595bf945e1c3a58392e01615c578d6c0d021dad933604d2962b3a512600155acbc43f7f6487f2a538aeb5466bb695e797afaca37c650a5f118435b178006555a6b004d9ad3660572d03aa43d586ed562a76538add049c07dab2ddaf71005dbe2acdbc22cf1abd797a7d005a6f8fda0cb291025f4668f605ed521f806c00903e0ee155d007189109bedcaee03a82d501c761b842495302fbab0dfb5c03001c6988932d718f5802f77dcd75de3bdfd50a03c553a0af0928af6a282fda3f000c74d4de97836e88924702f2c1765573bd4e65f313cf3be9708dcd9a00bee1007af9cab2d585e1c047ba2a60d1dd0e328585eef9d8065ea3949da8a73f916100ec1be03d7fa8528e229f5440d99669f627c6dad6e534c4711d56aabba9fcf2009575942fa9f099e81f2558db7bbed8b2dddf2a804577ffc3807f5e11e23dbe004cf1a304f697826f959a7d8bb1b6fd8834c4b1cf60a2ff4bf9d3fdbdbf5206007138e63ee53f4150d9517aec37571a2ebb246b5b76c900bb26ee216aff90da00b91ac376ab14bbc314bb61fba526ef1f06ee8f49ec0f52bd251bc3c097910600ca7e0494670c6c903e0ee167a05f3a32137cf9de876b59d7041c87e10a254d0009ecaf31ecf370e048439c6c89fbfdc3d02f35f13fe454fd217c2e313ca0bc00b03f47fb53a0a33e4925e882faa579e8f7a54eb7df9780fdc8a7f93f4a59b600ba3002f84887ff974cb4832a0bdd7bb01decaf949fa8ab5f07ae22bd5c15b800b60d6dd9dade22f82dd45c466229005a636659ed9a35335bead6ac5c36b96500ddb2e6954deb6240d7194a476c71202c8030eae9585ca5a733e8bac87021e8000a14af71c5a02ef0ab9698d66a2320c631bf4b47f1f12cd3a48bf804253e5100894f52d23fa2c41f53e24f28f12795f8d34afc1925fe4625feac127f8b127f009b127f87127f97127f8f127f9f127f4e897f40897f58897f4c897f42897f5a0089bfa8c4bfa0c4bfacc4bfa6c4bfa9c4bfa3c4bfafc47fa4c47faac47fa1c4007fadc47fa7c4ffaac4ffa9c4ffadc4ffa3c4ffa7c463313f4e9fa260b04f5c0030e2e213179bb8b8c4c5242e1a71b9d31257a219164b5889aeba58a24a2c49002596a012cd8158624a2c29259690124b468925a27a307f0928b1e49358e249002ce9249670124b365d2dd9fa327fc925d1a48abffc6209a501cc5f22490c6700886507c49224e2962abac2e25624ba3ae2162dbae4e2b62bfe2688bf86e2d6002a6eb9e216266e13a2c9164db4b88d886e85f854c768f0fd53f2579487f81400479af9d7f078e65fabe2fa14d7e464e62fcf3595f99fd398cefc65bd66307f001930b13c9858364c7c8e422c2926961a134b9089a5c9c49265626939f1d9870079cc5f7a4e2c4927963c13c370e2d30a62d8510ccd2d65fed04d1df38777c4007094187e12d31396337f9a8af8448098ae23a62c892966629a9d986a28a65b008aa5f8c51459314d584c9516d3c5c59479f1da80787542bc3e225ea111af110089e9a9e27532f14a9d78ad50bc5ad9cafc576cf731ff556bf1bab978e55e0c00311d66fe340031342786a8c550e809e60f858965c5c4326262d930b14c985800164c2c032696fd12cb7c8965bdc4325e0f307f992eb12c9758864b2cbb259600d912cb6a8965b41e61fe3259a29d7b9cf9ed9b58e64ab46b4f31bf3d13cb54008976ecff98df7ebd89f9edd69b99df5ebd95f9edd4db99df3ebd93f9edd2bb0099df1ebd97f9edd0fb99dffe3ccffc76e7835c3ec4fc36e7235c3ecafcf6e600e35c5e607e5bf349e6d719d1ce7c86cb6799dfc67c8ecbe799dfbe7c91cb970098dfb67c85cb5799dfae88eec13798dfa67c8bcbb799df9e7c97cbf798df9600fc80cb0f99df8efc98f98fbb441bf2332e3f677efbf14b2ebf627edbf11b2e00bf657ebbf17b2e7fe0f2472e7fe2f2672e7f617e1bf2372e7fe7f20fe6b72100ff627edbf112f3db8cff32bfad108d8168230ab8c4b974e2d2994b612cf3f7003cc632db1b64a4af8cd7363737ac5ddf5cdadc54bab6654df3caf56bb6956e0059d9bca2b46973c3c6c6354d5b30f16279dbee29e3e3366eacdd56ba725d7d00c3d6d2a696e6d2a6c6d2baa69675f59b30d1a18233b0785c26eed33e716d7d00fda9d33d28d3d12a7ad3b2333e723a8e3d793a89c6743d8d441313a79168e900e924ea5d7c1a89fa9e4ea229a793e8de8e2662ff0f44890a9f572d0200dbaf0010c3000000240b1f8b08000000000000ffed9d05781c3716c7b5dec44ed64e00ca6da8ad93b469dad0aed9c10d3649296d430d1bc371c00e3353b977d7837200afed518ff97acc773d666666861e48337addbfe5f1ae2791369a44f37def5b00e9cd48eff7341a8d76a4d114c6181bcefc2dcee54ad6718bc9dfb4fc4d9ede0096d29857d224672c229c0511e18c4784b35b4438bb4784b330229c4511e1ec001111ce9e1a39055b016bbfe9e64d182857dd8cc52c1ae7be24229cbd22c2d9003b229ce74584f3fc88705e1011ce0b23c2795144382f8e08e72511e1bc3422009c974584b34f4438fb4684b35f4438fb4784734044382f8f08e7151a39059b00fa9c5137ef9506ca55376369041807468071500418074780f1aa08305e1d0100c6211160bc26028c4323c0786d0418af8b00e3b008300e8f00e38808308e8c0000e3a808302623c0988a0063590418cb23c0581101c6ca0830564580b13a02008c351160ac8d00e3e808308e8900e3d808308ed3c87815cb6ce3e5ef04857700a2fc9d247f27cbdf29f277aafc9d267ded26e3d77399ce65069799721f15ca000d5c6ee47213979bb9dcc26516975bb9dcc6e5762eb3b9cce13297cb3c2ef300b9dcc1650197855c167159cc650997a55c9671a9e352cfa5814b2397262ecd005c967359c1652597555c567359c3652d97755c5ab8ace7b281cb462e9bb8b4007269e3b299cb162e5bb96ce3b25dfa522a7dd9c16527975d5c7673d9c3652f00977d5cf67339c0e52097435c0e7339c2e52897635c8e7339c1e524973bb9dc00c5e56e2ef770b997cb7d5ceee7f20097977079299797717990cbcbb9bc422900f3577279159787b83cac703ec2e5512e8f71799ccb135c9ee4f26a2e4f7179009acb335c5ec3e5b55c5ec7e5f55cdec0e5592e6fe4f2262e6fe6f2162e6fe500f2362e6fe7f20e2eefe4f22e2eefe6f21e2eefe5f23e2ecf71793f6b7ffe3f00c0e5835c3ec4e5c35c3ec2e5a35c3ec6e5e35c3ec1e5935c3ec5e5d35c3ec300e5b35c9ee7f2392e9fe7f2052e5fe4f2252e5fe6f2152e5fe5f2352e5fe7f2000d2edfe4f22d2edfe6f21d2edfe5f23d2edfe7f2032e3fe4f2232e3fe6f213002e3fe5f2332e3fe7f20b2ebfe4f22b2ebfe6f21b2ebfe5f23be90bcd75fa3d00973f28ba3f72f9930cff59fefe45fefe5539f66f5cfe2ec3ff90bfff94bfff0092bfff96bf2fc8dfffc8dfffcadfffc95f6a6c62f2b740fec6e56f37f9db5d00fe16f2df4f14fbe12296d9d2f237793a5b65b2babb67d4cf6b3c6bbf25a00c00e818a18b932ba0a3fa5d00baee5217075d2165073af2ab3be87a485d21e87a004a5d11e81252d70374b2b8584fa913f997485d5afe264f67ab48d6893c7be900cc53ce9deb2df32a017fce93ba5ea03b5fea7a83ee02a93b0f74174addf9a000bb48ea2e00ddc5527721e82e91ba8b4077a9d45d0cbacba4ee12d0f591ba4b0041d757ea2e035d3fa9eb03bafe52d7177403a4ae1fe82e97bafea0bb42ea0600808ec6c92e075da9d45d017564a0d4a5e56ff274b68a54b3c87390ce3ce53c00e0f7b38c1fe3257f01e826485d1c7469a9eb06ba8932d21d7493a4ae10749300a18c483745ea7a806eaad4f504dd342873ca6394d672aea816792675e6c97300157996e9cdd31bb32d6799f24d838d24944f855ebb29b41b934236481f87f0001896d92a204ced6a19c45301c761789492a604f6a70cfb5c061c6988932d510035b1dc35d7cb7afdf5b23c792ed7cb192cb3611da3fbf0d9542fc70383de7a00596da05e969dd3f5721ecb6c58c7a8df7636d5cb1b81416fbdacad77f7f1ac005be87ad9c4321bd631fa9f7036d5cb05c0a0b95e36bbf632eb16ba5e6e6299000deb18fd2f3d9beae50a60d05b2feb9b5dff32eb16ba5eee63990deb183d0700399beae56660d05b2f9b0cd4cb64d9b95c2fef66990deb183d773b9beae5410060d05b2f9b53ae5e66dd42d7cb875866c33a46cf79cfa67a799f0c8be7987f0096cf34fb83ee2f523700747f95bacb815f739dae72753aeb16ba4e3fcb321b00d64f1a57389beaf413322ceaea3f645d2d05dd3fa56e20e8fe25758340f76f00a91b0cba17a4ee2ad0fd47eaae06dd7fa56e08e8fe2775d7808e062986822e002675d782ae40eaae035d5cea8681ae9bd40d075d77a91b01ba42a91b2975e200990e8db97c4aea8a209fb4fc4d9edee68d05122f6d31259e86f070732cc9120060413b23f5da294f40d977c5e791c0a2b55de55b02f2ef0acb2860d1dc1e7b00fd9694de3cbd733a4229c704d81901fe68be1778ed538ab52f478a635b995200ca3601fb91af5c2f5f59b6f6b31cf882ee5fbaef9bc2e7c14ad988e6e7eb600053f375e8ddabe93aa7f5b188816cc5e1985dc519ae6f0397ee365170d17d8700f2a5b8c1f6ef5cb3ebd5b9ab143be2dcfe046ceaad73a966ac73a27fb807180082eadc54a873bf90ba62d83f0c74941eefebb6b473828fdab7547ef9cabaca009754f80cdc8f5238f790f27576f5df4f307f71edd0f54276e2b0ffd30599e3005e00a6617a99cac2f6fb86192b9fb264d87e7719b0e8ae2326cebf81fe925700a72a02ce4fd0ffde7228af33f1bfd7b13a56c7ea581dab6375ac8ed5b13a5600c7ea581dab6375ac8ed5b13a56c7ea58a3c48a63f938c72568acfc4cf191ce00e4d886f099e616e158f99db18c4dbdcfe8cbbcb1722a73316e590a0c642b0e00c73c12cb70dd2bc3386e896394eab8a581792edef9c3792e698893ad62e0c70039379ae71da4b02c29dfb3d76e598389f78ac4bbb0e2fd7baa4f49c50f9c4b00738da21375f2f9828cbfbac7b3c28ead191c7f6d37a70dede81d1bf3db076a008b44d196b24cfb60e0be91a280b05b29f312edd240d6b15d8ec331af9527a2003733779fe86cbcbb02caa152afdd24cef765b2fce9da205b0908d3b1225d1500945f29945f25941f1df31668d7e7c035a47bce06ce0d61c08a5b1ac2383ead00f79cfa63e5652158f03c6b1e834e19a8b34913f551e451c53a9e1fec2bd1fe004a28af2acde5a55e176988239f6375ac8ed5b13a56c7ea581dab6375ac8ed500b13a56c7ea581dab6375ac8ed5b1468515df2b27ce041c97b2802f0ff30abc0067f7b4e606e52dc62e26c3d885c9b1301a5319a2f81a8763f61564b8ae97e10062d6712e4167e74ff3b3fbace78f6c15832f38de61623cad5c61397bedfa6300e57aafc7cc5839d5a72ac50f3aa738564c3a1ce7c3b58070fe46b9a23b53e70003af9972d05118dfa7d55dc682af5ae645eb3ed1f837d98ac3314b6599d2380074b5661e13edbac8a346e6d58d75ac4f71d8df086d5ab30c07b55f627f5bc0007edab28db35299095f47ebf5d53b9ff47d003a9fa303ec8ed56b378576691d002fb241fa38845b0b32e53136137cb17c89595c07b501c761b842495302fb6b000dfb3c1a38d210275ba29eac843ad506f76fddf73ff417cbe56a2817da8f7d001713fda81ae028651ddb149c13499ce23aa23a8a6d72ad01be6ae04b43bc1600f84887f350c80f6c4f70fee2b93a3fe908dc1782e6f450da21c0aca9feb76300ae5298d5be02ce093aa9dccb4cf4473b9b5365f07f56bb7347e54f73aac856008275fccfa7f6054a59c7ff3fd8177800dab58f435f8bea25f6ff2b159da9760007fd4e439c6c615f0bfdaeecc46f5cc7496f5fc7e725aeee0a07d9c2fafab000728dd500731a9847415a3ae63148cb58fbf699e69e627fb44a394e7f5fa52c00b0af42edc368f0818e795ab95ec768e631d01ff3aa3bf605ca02fca3fdaf8700ebe959e85bd23928877c9e0bd84f5bb6be279599f075bc5e5fbdf349df3ea500f3393ec06e5aafdd14daa5be27e54dfa3884df57105c3654bec42cae83710100c761b846495302fbc719f679bcc2a49e4f514fde0c75ea39e87beaee53a1bf00582e43a05c687fd0b33e3a5ed467ba1ef05ea1fbbac4ff27942fc5b3fd8fc0007b9dfefe5ec7f7754a59c76770f86c10dfa3c167839ad7004be2fb08c3c0e600f3e66c7a6541df0ea37c7b290ce7a25d5bd632c6e76e05c037c200dff0107c0023808fd2c5814ff7fb49a7ba2e32fe07ee067cbadf213bd5b5924b205d77e000d3bd7e72026c76852f097c94ae10f84cbc17950cc197023e5c7b987e35bf7300923ad5774ef0fedb03f874dfd3c2be8712b486f38bdf9666fa9fd1e358405700f870dc14efc9c4a7fb3942d8e7cb382e82ffe94cf165bb6f197cce5186cf1500ba522ed8efc432125bd0f310d3fff9295f8a570313e97a196449282cb9ca2f0088af37f0d518e0ab0ec157037c94ee3ce0d3fd9f27ec7f6f7cb64ce9ce073e00ddff7112acfd78402e3efcdf43e92e003ebdcf5b7cbed121f8c6001fa5bb1000f8748fef2458fb6f6de7e21b0b7c94ee22e01b67806f6c08be71c047e92e06003ecdcf833cbe7121f8f0190aa5bb04f82618e01b1f826f02f051ba4b812f6d00806f4208be34f051bacb806fa201be7408be89c047fa3ec037c900dfc4107c0093808fd2f505bec906f82685e09b0c7c94ae1ff04d31c0373904df14e0a37400fd816faa01be2921f8a6021fa51b007cd30cf04d0dc1370df8281d7e9bee7a00037cd342f05d0f7c94ee0ae09b6e80effa107cd3818fd25d097c330cf04d0f00c13703f8281dfeaf9d69806f4608be99c047e9ae01be1bf4f279ffdf6686e000bb01586ed2cb529180fcbbc27213b0dca8972565c03f6f6cf366cd798a3c6e00611dcf0fb197c0fe9ba1bc6ed15c5e31b049f9521cf91cebb9cd2a58662a9c0009386ea6057ca4bbd1204b4261115bb6b62e880fcfe52c037cb784e09b057c004175ed56bd7cde7d6b5608be5b81e576ad2ce5deb8ecad21586e0796dbb4b200f8f72dbdfef9f798d9016549764a603f9ef3d99a7d8b814dca97e2c8e7581d00ab6375ac8ed5b13a56c7ea581dab6375ac8ed5b13a56c7ea581dab6375ac8e00d5b13a56c7ea581dab6375ac8ed5b13a56fdac826596c29980e36659c047ba00db0cb2241416b1659b2712c487e7728e01bed921f8e6005f505d9b6b806f4e0008beb9c03727806f9e01beb921f8e601dfdc00bef97af9bc3953f342f0cd070096055a59fcefe2cd0fc1b20058eed0cae2cf99d2eb9f3f676a614059929d1200d88fe77ca166df626093f2a538f23956c7ea581dab6375ac8ed5b13a56c7ea00581dab6375ac8ed5b13a56c7ea581d6b545805cb3c853301c7cdb3808f747700186449282c62cbf69c3d880fcfe522037c0b43f02d02bea0bab6d800dfa210007c8b816f5100df12bd7cde98cee2107c4b8065995e166ffd962521589601cb0052bd2c2903fe79633a75ac6359929d12d88fe7bc4eb36f31b049f9521cf91c00ebb9cd2a58162b9c09386eb1057ca45b6a9025a1b0882d5bbb14c487e7b2de00005f5d08be7ae00baa6b0d7af9bc7b4c7d08be066069d2cae2cf1b6808c1d200042c8d5a59fc7b8c5efffc7b4c734059929d12d88fe7bc59b36f31b049f95200bcd99c5dcfffe539fc5f1ec0b13c8ffe235f57596f8e10ab2b5757aeae5c5d00b9ba7275e5eacad595ab2b5757aeae5c5db9ba7275e5eacad595ab2b5757ae00ae5cbbce2a58ea15ce041c576f011fe91a0db2241416b1657b761fc487f56e008501bee521f856005fd075b1d200df8a107c2b818fd2e1b5b04a2f9f374eb4003204df2a6059a395c55f937f55089635c0b25a2b8b3f4ea4d73f7f9c646d400059929d12d88f7572ad66df626093f2a538f29d8daccd11627575c00cabab03008ed5d501c7eaea80637575c0b1ba3ae0585d1d70acae0e385657071cabab03008ed5d501c7eaea80637575c0b1ba3ae0585d1d70ac67ba0e0896950a67028e005b69011fe9561b6449282c62cb364f24880febdd3a037c6b43f0ad03bea0eb00a2c500dfba107c2dc0b72e806fbd01be96107ceb818fd2e1b5ba412f9f3767006a7d08be0dc0b2c900cb86102c9b8065a35e969401ffbc3953ad016549764a00603fd6c956cdbec5c026e54b71e48b0aab6059af7026e0b8f516f0916ea341009684c222b66cd74f101f9ecb36037cad21f8da802fa8ae6dd6cbe7b53f6d2100f83603cb56032c9b43b06c05962d7a595206fcf3dac26d016549764a603f9e00f36d9a7d8b814dca97e2c8171556c1d2a67026e0b8360bf848b7c5204b426100115bb6eb27880fcfe576037cdb42f06d07bea0bab6c300dff6107c3b806f7b0000df4e037c3b42f0ed043e4a9700be5d06f87686e0db057c94aed8209f60e900a5b0f4525884dddd7aed7af7b55dacebe5b21bca05cb486c09d88fcc7b0c9400d56e858fe27b808974bd0cb22414965ce517c4d71bf8f61ae0db13826f2ff00051baf3806f9f01bebd21f8f6011fa53b1ff8f61be0db17826f3ff051ba0b8000ef8001befd21f80e001fa5bb10f80e1ae03b1082ef20f051ba8b80ef9001be008321f80e011fa5bb18f80e1be03b1482ef30f051ba4b80ef8801bec321f88e00001fa5bb14f88e1ae03b1282ef28f051bacb80ef9801bea321f88e011fa5eb00037cc70df01d0bc1771cf8285d5fe03b6180ef7808be13c047e9fa01df4903007c2742f09d043e4ad71ff8ee34c0773204df9dc047e9f07fc55d7af9bcfee9009d21f8ee02967bf4b278eb99df1582e51e60b95b2f4bca807f4991e7bd9af3001479dcc73a9e1f622f81fdf74279dda7b9bc626093f2a538f239d6739b55b000dca97026e0b83b2de023ddddc0a2bb2d103e0f957951deddb88c2ecad8d4dc00d7a810fed33daf50e64b0c642b0ec7ac4f64b8c64bae62d84fe70afb3078fe0074f73563ac7d5f290d71b2550cbe1c0316ddfdca186bdf2f4a5b66d7443f3f004c3ff5a8399624f67dd18e89ff8661fedb1c36c882ff97d08ee6ffeb5ebb7400adcc8bf216d7ffec2263be79ed129d476a97ae557c8dc331b3a15d9a1fd02e0019bc0e92eaf5570a76c916fee73c0e2c9a9f0d244b80a380193b3fa9ae3e0f00a16da6452ce32d62a9b188a5cc2296e116b10cb088e5528b588658c472be45002c2b2d62e969114bdc2296a116b14cb088a5d62296728b584658c472b9452c009759c47281452c098b58aeb588a59b452cf32c62b9ce221693cf4fc2b2a42d0062196d114b85452c232d62b9c222963e16b15c68114bb1452cf516b174b78800e56a8b586659c432d122963116b1545ac432ca22962b2d62e96b11cb4516b1009458c4d2cb2296428b582659c432d62296c116b15459c492b488a5d422967e0016b1989cc31f96a5b7452c4516b1ccb088e52a8b58265bc432ce22969316b100545bc432d022964116b1a42c621966114b7f8b582eb18865bd452ce759c472008d452c3d2c62596c114bec0cb32458c7b9caf82e6929e8689e2fce5fa5776f008f80ae20c006cdf339043a1af7a53c0ab93c57dc91a100d2d0bbc8f10086c30001ac0702d29a2e73b4938638d92a06860316b02cb688a587452cd758c4729e00452ceb2d62b9c42296fe16b10cb388256511cb208b58065ac4526d11cb498b0058c659c432d92296ab2c629961114b91452cbd2d62b9d822967e16b1945ac40092b488a5ca2296c116b18cb5886592452c8516b1f4b288a5c422968b2c62e9006b11cb9516b18cb288a5d222963116b14cb4886596452c575bc4d2dd22967a008b588a2d62b9d022963e16b15c6111cb488b582a2c62196d114bda2296a31600b15c6711cb3c8b58ba59c472ad452c098b582eb088e5328b582eb788658445002ce516b1d45ac432c12296a116b1c42d62e96911cb4a8b58ceb7886588452c00975ac432c02296e116b19459c4526311cb788b58665ac452902716fc864c1a00e287c1ee7ebd76bdef09ecd39ba7b716ef5e9957a1cc97b8c9561c8e99206f00b2342781f462a3f9bbfbe17c1c568e2b62fabfc9257c18c4da9f8f41ceee1900b3abb98e6af9a6d97ee033f1cdba7d21f8f61864c1efa4a11dcddf39f4d60d00a7e76294b7781e34a767c6a6deef19a49a45999e9079515b450c41df33a8810075c3ef905cb86ef85e96d98e830fd4669d803c69ff6268fff0db03c358267f005a8f7c38e8e879e608d01d91e191a0a3fbc828d051bb9a041ddddf52a0a33a005e063aaa0be5a0a37a51013a3a8734568bdff7c4f55f747f8735c6da7f4734000df11dc047dfbfc46f8752b80a7494a61a74f4bdd61ad0d137666b4147dfc5001d0d3afa86ef18d0d17787c7828ebe3b3c0e74f44deff1a0a3ef904f001d7d00333d0d3afacefb44d0b5c8f024d0ad93e1c9a05b2bc33340b74686a9af26ce00ef2a4527ceef0a8525797a9b777ec90ee54bf115c0b75a8657818ec2b3807900b9a213cccd0698972bcc146f063ee25f0e3a0acf03e6264527981b0d30372900cc146f043ee26f021d8517037383a213cc7506981b14668ad7011ff137808e00c2f5c0bc4cd109e6a506989729cc145f0a7cc4bf0c74145e09cc4b149d605e0064807989c24cf145c047fc4b4047e1f5c0bc50d109e6050698172acc145f00007cc4bf1074143e69986f97c2b74be1336577b56277759eecae50ecaec893dd0066c56e739eec362a761bf364b74eb15b9727bb4b15bb4bf36477916277519e00ec9e6bf5f94cb51be75a7d3e53edc699ba8edc7d303f76dd7d303f76cfb5fb006057aedff97aed7adfa15ec0da6fd99e99ce07963b34978101ffbcb19ab99a00f31479cc813259a0944d09ec9f0be535477379c5c026e54b71e48b0a6b027400c74147fb8f816eb60ce3da39b7cbf011d0dd26c3b84ecead327c1074b7c8f00001d0d1f7dff783ee26195e0bba1b65780de86e90e1d5a09b2ec3ab4077bd0c00af00dd34195e0ebaa932dc0cba2932dc043afa0e7023e8e87bcf0da0a36f2c00d7818ebe87bc0c74f4ddeaa5a0a36f362f01ddfd32bc08740fc8f002d0bd440086ef00dd4b65782ee85e26c3fb40f7a00cef01ddcb657837e85e21c3bb40f7004a19de09ba57c9f00ed03d24c3db41f7b00c6f03dd2332bc15748fcaf016d0003d26c39b41f7b80cb781ee09196e05dd9332bc0974af96e18da07b4a86378000ee69196e01dd3332bc0e74af91e185a02b90e1f9a08bcb305eab34ef7836e800e83d9ddb415728c3b781ae48866f051dad55740be8682ed9cda0a379bd3781008ede83b91174f4aee60da0a37749a7838ec6d0af071dad0f340d74347f6b2a00e8685eef14d0d17b30f89d6e7a5713bfbd4eeff0df0d3a5a7fe71ed0d1fca8007b41477378ef031dbdf3723fe8e8bdcc0740d74f865f023a5a6be7a5a0a3b900502f031dcdd77d1074f47ecbcb4147ef60be0274a532fc4ad00d94e157818e00c6b21f02dd60197e1874b466c623a0a377d61e051dcd757b0c74d7c8f0e3a000a3f99c4f808ee6b33f09baeb64f8d5a01b26c34f818ec61d9f061d8d3b3e03003a1a77a46b515c07fac76dfdf1f113acfd96adaf47f6058bdeefa9fb63c8c70081210d36ae03bb47b4daf5fb214715bbc441b64a58c76f4be398f05ee03b6000a05ca8bf4163ebea3b38713866aa6c0ca90d23bdd80606f8a0ce0d4a40f820001c47b6f6417e74df2d80340760ff6e081f52d2e01c90dd6067976247fbd87600caefafef0476b2b903d8c8fe4ee0d8a69343d63dea5750be54d7b16f413a3a00569dcfa17b1e9db07994b5dfb2b50b38b7ee905e166f1edc616048830dfcc600a2deebce3f370715bbc441b64aa09cf05aa16be118f0ed35502e742d51bb40000c642b0ec7d429ed02e9c57622c00775ae5202c2fbe0b8bd327c04f2a3ebb90000d2ec85fdf85c63bf924694e931e5389c5342764499d2f59096bfc9d3d96400bbb003d8c9e6766023fb3b8063ab4e0e59f7e8faa77ca9aee3ff0bd2d1b1a2005d985d9429333aafd8ef3ca6e8c4e1470df01f63edf9298ef71ebacfe275a200b72d2b4b9e4e5ba6bbaf61a0ad4eea6f736bbdc70707a14c8e2a655302fb0f0041791dd45c5ed8f653be143f68ceae374def400eff0f047098b80775e63ff2007595f5d01966d56fb7d99b26b83f87fffb0338f6e7d1fffdc6ec567ad347f700e5f07f5f0087eeb9e0d9fcdf67cc6ead77fef7e6f07f6f00c7de3cfabfd79800ddaa7a91c79e1cfeef09e0d03dbf3d9bffe6e6d5377953a077e7f07f77008700e679f759fddf6dcc6ebde7ffae1cfeef0ae0d89547ff7719b35be74d95df9900c3ff9d011c3bf3e8ff4e6376ebbce9f43b72f8bf2380c3c4fb029df9bfc39800dd4aafafba3d87ffdb0338b4fe77cce1ff7663766bbdd74cb6e5f07f5b0087008967599df9bfcd98dd06effeb73587ff5b03384cfc67efccffadc6ec367bed00ff961cfe6f09e0d89247ffb718b35be9f9bf3987ff9b033836e7d1ffcdc6ec005679ed7f5b0effdb0238daf2e87f9b31bb8dde2b66ad39fc6f0de068cda3ff00adc6ec367bd33a36e5f07f5300c7a63cfabfc998dd2aef59cdc61cfe6f0ce000d8a89523bbff1b8dd92df7feff6fc8e1ff86008e0d79f47f8331bb7575228f00961cfeb70470b4e4d1ff167376bdfbdfba1cfeaf0be0589747ffd719b35be700d5ffb539fc5f1bc0b1368ffe932dfd76cbbd57a7699ea1d882fca7fdc8b146002b4776ffd798b3ebf5ff57e7f07f7500c7ea3cfabfda98dd4a6fcc72550eff00570570accaa3ffab8cd96df4dabf1539fc5f11c061e27dfacefc5f61cc6ead00e7fff21cfe2f0fe0589e47ff971bb3dbe0b57fcd39fc6f0ee030b1364167fe00371bb35be63dff6acae17f530047531efd6f3266b7c2abff8d39fc6f0ce03000b1ce4367fe37825dddf31bf03db04299ef50a50ce270cce57262746f850dcb008ed2e39a39e84383561ffcb94c759df8d0003ed03183c18722a67dfd8b0a03003e7acf6997c9bcc43c9de301fed1fea1c599e3ae93e1049c8313904f6dc07e00dab2cd73a13213be2ed1eb6b12df99a3f3b924c0ee42bd76dbbdab1793423600481f87700dbd24c0daaf6941e58beb6d2c0d380ec38d4a9a12d8bfd4b0cf9d00ad2142b6443d1901758aea8c81f94829f417cb6528940bedc7795fbaafb7a000f560d43645b004bd1f457514e7c89958afa64ee1a3f852e023dd61e0233f9600c95f714e47176558476a65f5e7a0d3ba67743dd3bb16642b0ec7cc50ee31a40017db40f94be9715ddb51e0238571ad36b2350c74b4f6da08485baee844995400682d13fffc911dca97e2b87e1bad03579e5fbeb2aef295297c4510d6c4e295005599c21264b7da805db50ca80e551bb65ba9d84d297613701e68cb76bfc6b500feaa34f38a3c6bf4e6e9f501680d3f6a33c8460a7c19add917b44b7d00b24100fa388457431f607426f862bb826b1356071c87e10a254d09ecaf36ec730d7000a4214eb6c43d6219dcf735d779ef7c572b0c144f81be26a0bcaaa1bc68ff2800d0517b5f0eba114a1e09c807db55cdf53a95cd4f3cefa4c3753b6b02f86af500f29565ab0bb5c047ba2a60d1dd0e328585eef9d8065ea5949da8a73f9161ec001be03d7fa4528e229f5440d99669f627c6dad7e534c4716d57aabba9fcf2950075952fa9f099e81f2558fb7bbed8b2dddf2a804577ffc3807f5e11e23dbe4c00f1a304f697826f959a7d8bb1f6fd8834c4b1cf60a2ff4bf9d3fd7db05206710038e601e53f4150d9517aec37571a2ebb246b5f76c900bb26ee216aff90dab9001ac376ab14bba314bb61fba526ef1f06ee8f49ec0f52bd251ba3c0973106ca007e3494670c6c903e0ee1d741bf744c26f8e2bd0fd7c7ae09380ec3154a9a1200d85f63d8e75ae048439c6c89fbfda3d02f35f13fa4b3fe103e97a80d282fec00cfd1fe14e8a84f5209baa07e691efa7da953edf725603ff269fe8f5296ad2e008c063ed2e1ff2513eda0ca42f71e6c07072be527eaead781ab482f5705ae9700435bb6b6b7087e0b359791585e80d6ad69a85bb366565bfd9a950dd3dad63500b4ae6c591703baee503a628b03610184514fc7e2ca3fdd41d743860b4157a000788dab10f5805fb5c4b4561b013191f95d3a8a4f6299265dc4272bf1294a7c00aa92fe5125feb8127f52893fa5c49f51e2af55e2af57e2cf2af13729f1b72800f1b729f17728f17729f1f728f1f729f1f72bf10f29f18f2af14f28f14f2bf100e795f81794f89795f8d794f83795f87794f8f795f88f94f84f95f82f94f8af0095f8ef94f85f95f83f95f8bf95f87f94f8ff94782ce6c7e9f3160cf6890b46005c7ce262131797b898c445232e775a364b34c362592cd15517cb5e8965aec400b256a23910cb568965aac4b25462192ab1ec541fe62f2b25969112cb46896500a2c4b2506219a82b25db40e62fe3249a54f1975f2ccb3484f9cb2e89e10cb100948158e644dc52455758dc8a445747dca245975cdc76c5df04f1d750dc5ac5002d57dcc2c46d4234d9a28916b711d1ad109fff1807be7f4afe8af2109ff7480033ff1a9ec4fc6b555c9fe29a9cc6fc25bfa633ff131d3399bf54d88dcc5f5a004c2c39269622139fb810cb9489e5cbc4b26662b933b10c9a58ae4e7c4a623e00f397b313cbdc89213831dc283ed72086e5c4d0ce32e60febd4337f284a0c3d0089a909627ac672e64fd3119f1d10d395c4942d316d4d4cdd13d317c5144eb100bcbf98ca2aa6f38a29cd625ab798da2ea6f78b571cc46b1ee25517f1ba8f7800e549bcf6255e7d13afff895720f732ff55d8fdcc7f255abcc22e5e0d17434c0047983f0d400ccd89216a31147a92f9436162a932b13499588a4c2c3d26961a00134b8b89a5c4c4d26162a930b134d883cc5ffa4b2cf52596f6124b7989a5bb00c4525d6269ae4799bff49668e79e607efb2696ce12eddad3cc6fcfc4d257a2001d7b1df3dbaf3730bfdd7a23f3dbab3733bf9d7a2bf3dba7b733bf5d7a27f300dba37733bf1d7a2ff3db9fe798dfee7c80cb0799dfe67c98cb4798dfde7c8c00cbc799dfd67c92f97546b4339fe1f259e6b7319fe3f279e6b72f5fe4f225e600b72d5fe1f255e6b72ba27bf00de6b729dfe2f26de6b727dfe5f23de6b7253f00e0f243e6b7233f66fee32ed186fc8ccbcf99df7efc92cbaf98df76fc86cb6f0099df6efc9ecb1fb8fc91cb9fb8fc99cb5f98df86fc8dcbdfb9fc83f96dc8bf0098df76bcc0fc36e3bfcc6f2b446320da88022e712eddb874e75218cbfc3d8f00b1ccf61a191928e375adad4d6bd7b796b6b694ae6d5bd3ba72fd9a6da55b5600b6ae286dd9dcb4b1794dcb164cbc44deb6fbcaf8c48d1bebb695ae5cd7d8b400b5b4a5adb5b4a5b9b4bea56d5de3264c74b8e0342c9e908907744c5cd7d8d80079ba87643a5a996f4676c6474fc5b1a74e25d1f89ea790684ae214122d3b950044038a4f21d1a0534934fd5412dddfd544ecff937dd038ab2d02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex b/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex new file mode 100644 index 00000000000..225f04bb119 --- /dev/null +++ b/yarn-project/circuits.js/fixtures/ContractInstanceDeployedEventData.hex @@ -0,0 +1 @@ +0000000085864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631173b1e288f0f29f945ffa7b4ec2b69393e32b78501d0f193288e4a886a9f6e18000000000000000000000000000000000000000000000000000000000000000113554cdde23fee1efdb34bb3f685929e9098b8328083970984754948007e11ea0798434d6f2adf997c4fe3d14cb8468aa3cbf7a70d8c499c3c775fc8feff67960f68e30db11bc73392acfc02600ad1177cbe0d17cbbb5d3086a592b736f414a8000000000000000000000000507a47e77fc808e31716c47865eb372b2a487b7505331ff473c938df8b7a6dba01cf45bd6b029d4aeeff7e76953b31ef2510f7b80000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 83c040e356d..458fc20b0ff 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -26,7 +26,7 @@ "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "remake-constants": "node --loader ts-node/esm src/scripts/constants.in.ts && prettier -w src/constants.gen.ts", + "remake-constants": "node --loader ts-node/esm src/scripts/constants.in.ts && prettier -w src/constants.gen.ts && cd ../../l1-contracts && ./.foundry/bin/forge fmt", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, "inherits": [ diff --git a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap b/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap index 3062c58963d..b169f23ce2b 100644 --- a/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap +++ b/yarn-project/circuits.js/src/abis/__snapshots__/abis.test.ts.snap @@ -1,93 +1,50 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`abis Computes a callstack item hash 1`] = `"0x037cb5ba672a7c461e23cf22ae618757ab4f1a912f3fdc93b2b2800cfe57bb91"`; +exports[`abis Computes a callstack item hash 1`] = `"0x17095bbb9e3e104dc520b6eec9338e9b6ce1fdc0f3a66b06d5ca90b15909ad0e"`; -exports[`abis Computes a callstack item request hash 1`] = `"0x2c36008a759d932a3a1986429aa295e2c2d4e62c33197a7d259750d29347bf30"`; +exports[`abis Computes a callstack item request hash 1`] = `"0x28cb4c264eb11e13c77a5e60b251a6b3edfb4cfed786c4f1ec5e1749fede9b78"`; exports[`abis Computes an empty nullifier hash 1`] = `"0x066e6cdc4a6ba5e4781deda650b0be6c12f975f064fc38df72c1060716759b17"`; exports[`abis Computes an empty sideeffect hash 1`] = `"0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed"`; -exports[`abis compute private call stack item hash 1`] = ` -Fr { - "asBigInt": 20809484660315254497535468009354600907499263083154533860853878665971818104219n, - "asBuffer": { - "data": [ - 46, - 1, - 192, - 60, - 242, - 95, - 113, - 243, - 178, - 218, - 79, - 199, - 55, - 206, - 59, - 194, - 234, - 24, - 158, - 215, - 200, - 157, - 95, - 167, - 67, - 42, - 204, - 172, - 237, - 37, - 5, - 155, - ], - "type": "Buffer", - }, -} -`; - exports[`abis compute public call stack item hash 1`] = ` Fr { - "asBigInt": 4942803204430729321299247114280769628204291639882373728884145897482860239103n, + "asBigInt": 6902726350534637945034037933577508446422215007904358955522461123516426791152n, "asBuffer": { "data": [ - 10, - 237, - 135, - 8, - 121, - 161, - 111, - 170, - 23, - 173, - 20, - 73, - 240, - 78, - 59, - 30, - 113, - 136, - 151, + 15, + 66, + 205, + 254, + 91, + 241, + 101, 117, - 250, - 42, - 35, - 186, - 162, - 159, - 250, - 242, - 152, - 210, + 214, + 154, + 136, + 128, + 223, + 11, + 120, + 249, + 245, + 174, + 102, + 132, + 69, + 153, + 88, + 179, + 36, + 144, + 98, + 110, 24, - 255, + 250, + 168, + 240, ], "type": "Buffer", }, @@ -790,41 +747,41 @@ Fr { exports[`abis hashes function args 1`] = ` Fr { - "asBigInt": 11839099223661714814196842233383119055519657007373713796026764119292399532830n, + "asBigInt": 13773950327711008256617416059663646210697922258755635023101062905870427579114n, "asBuffer": { "data": [ - 26, - 44, - 177, - 84, - 151, - 13, - 83, - 84, - 26, - 98, - 206, - 96, - 113, - 195, - 152, - 109, - 8, - 146, - 63, - 234, - 71, - 75, - 232, - 160, - 170, - 26, + 30, + 115, + 199, + 148, 191, - 135, - 24, + 130, + 160, + 100, + 98, + 205, + 48, + 10, + 124, + 139, + 218, 39, - 59, + 47, 30, + 253, + 79, + 200, + 107, + 56, + 53, + 41, + 130, + 26, + 237, + 106, + 243, + 98, + 234, ], "type": "Buffer", }, @@ -833,41 +790,41 @@ Fr { exports[`abis hashes many function args 1`] = ` Fr { - "asBigInt": 9368119665570837995905174888524883816390941475336228173888734493993721486827n, + "asBigInt": 5019561503322397537490243039227402098195702132635946562396386724242519444026n, "asBuffer": { "data": [ - 20, - 182, - 42, - 246, - 214, - 208, - 1, - 110, - 254, - 196, - 157, - 194, - 3, - 246, - 106, - 69, - 102, - 180, - 241, - 249, - 168, - 116, - 85, - 53, + 11, + 24, + 248, + 156, + 4, + 206, + 67, + 253, + 74, + 84, + 242, + 151, + 150, + 30, + 97, + 225, + 13, 209, - 138, - 127, - 164, - 10, - 109, - 93, - 235, + 17, + 48, + 60, + 254, + 13, + 43, + 30, + 121, + 227, + 133, + 97, + 87, + 74, + 58, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/abis/abis.test.ts b/yarn-project/circuits.js/src/abis/abis.test.ts index ad6a2070b3f..00c3d95aa57 100644 --- a/yarn-project/circuits.js/src/abis/abis.test.ts +++ b/yarn-project/circuits.js/src/abis/abis.test.ts @@ -2,6 +2,7 @@ import { times } from '@aztec/foundation/collection'; import { AztecAddress, + EthAddress, Fr, FunctionData, FunctionLeafPreimage, @@ -14,7 +15,6 @@ import { import { makeAztecAddress, makeEthAddress, - makePrivateCallStackItem, makePublicCallStackItem, makeTxRequest, makeVerificationKey, @@ -27,7 +27,6 @@ import { computeFunctionSelector, computeFunctionTreeRoot, computeNullifierHash, - computePrivateCallStackItemHash, computePublicCallStackItemHash, computePublicDataTreeLeafSlot, computePublicDataTreeValue, @@ -127,7 +126,6 @@ describe('abis', () => { }); it('hashes function args', () => { - // const args = Array.from({ length: 8 }).map((_, i) => new Fr(i)); const args = times(8, i => new Fr(i)); const res = computeVarArgsHash(args); expect(res).toMatchSnapshot(); @@ -146,7 +144,7 @@ describe('abis', () => { }); it('computes zero contract leaf', () => { - const cd = new NewContractData(AztecAddress.ZERO, AztecAddress.ZERO, new Fr(0n)); + const cd = new NewContractData(AztecAddress.ZERO, EthAddress.ZERO, new Fr(0n)); const res = computeContractLeaf(cd); expect(res).toMatchSnapshot(); }); @@ -157,12 +155,6 @@ describe('abis', () => { expect(hash).toMatchSnapshot(); }); - it('compute private call stack item hash', () => { - const item = makePrivateCallStackItem(); - const hash = computePrivateCallStackItemHash(item); - expect(hash).toMatchSnapshot(); - }); - it('compute public call stack item hash', () => { const item = makePublicCallStackItem(); const hash = computePublicCallStackItemHash(item); diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index 9c1b9c35b81..38106b6927a 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -7,22 +7,27 @@ import { boolToBuffer, numToUInt8, numToUInt16BE, numToUInt32BE } from '@aztec/f import { Buffer } from 'buffer'; import chunk from 'lodash.chunk'; -import { FUNCTION_SELECTOR_NUM_BYTES, FUNCTION_TREE_HEIGHT, GeneratorIndex } from '../constants.gen.js'; -import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; import { + ARGS_HASH_CHUNK_COUNT, + ARGS_HASH_CHUNK_LENGTH, + FUNCTION_SELECTOR_NUM_BYTES, + FUNCTION_TREE_HEIGHT, + GeneratorIndex, +} from '../constants.gen.js'; +import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; +import type { ContractDeploymentData, FunctionData, FunctionLeafPreimage, NewContractData, - PrivateCallStackItem, PublicCallStackItem, - PublicCircuitPublicInputs, SideEffect, SideEffectLinkedToNoteHash, TxContext, TxRequest, - VerificationKey, } from '../structs/index.js'; +import { PublicCircuitPublicInputs } from '../structs/public_circuit_public_inputs.js'; +import { VerificationKey } from '../structs/verification_key.js'; /** * Computes a hash of a transaction request. @@ -148,10 +153,7 @@ export function computeFunctionTreeRoot(fnLeaves: Fr[]) { */ export function hashConstructor(functionData: FunctionData, argsHash: Fr, constructorVKHash: Buffer): Fr { return Fr.fromBuffer( - pedersenHash( - [computeFunctionDataHash(functionData).toBuffer(), argsHash.toBuffer(), constructorVKHash], - GeneratorIndex.CONSTRUCTOR, - ), + pedersenHash([functionData.hash().toBuffer(), argsHash.toBuffer(), constructorVKHash], GeneratorIndex.CONSTRUCTOR), ); } @@ -224,9 +226,6 @@ export function computePublicDataTreeLeafSlot(contractAddress: AztecAddress, sto ); } -const ARGS_HASH_CHUNK_SIZE = 32; -const ARGS_HASH_CHUNK_COUNT = 16; - /** * Computes the hash of a list of arguments. * @param args - Arguments to hash. @@ -236,13 +235,13 @@ export function computeVarArgsHash(args: Fr[]) { if (args.length === 0) { return Fr.ZERO; } - if (args.length > ARGS_HASH_CHUNK_SIZE * ARGS_HASH_CHUNK_COUNT) { - throw new Error(`Cannot hash more than ${ARGS_HASH_CHUNK_SIZE * ARGS_HASH_CHUNK_COUNT} arguments`); + if (args.length > ARGS_HASH_CHUNK_LENGTH * ARGS_HASH_CHUNK_COUNT) { + throw new Error(`Cannot hash more than ${ARGS_HASH_CHUNK_LENGTH * ARGS_HASH_CHUNK_COUNT} arguments`); } - let chunksHashes = chunk(args, ARGS_HASH_CHUNK_SIZE).map(c => { - if (c.length < ARGS_HASH_CHUNK_SIZE) { - c = padArrayEnd(c, Fr.ZERO, ARGS_HASH_CHUNK_SIZE); + let chunksHashes = chunk(args, ARGS_HASH_CHUNK_LENGTH).map(c => { + if (c.length < ARGS_HASH_CHUNK_LENGTH) { + c = padArrayEnd(c, Fr.ZERO, ARGS_HASH_CHUNK_LENGTH); } return Fr.fromBuffer( pedersenHash( @@ -291,7 +290,7 @@ export function computeTxHash(txRequest: TxRequest): Fr { pedersenHash( [ txRequest.origin.toBuffer(), - computeFunctionDataHash(txRequest.functionData).toBuffer(), + txRequest.functionData.hash().toBuffer(), txRequest.argsHash.toBuffer(), computeTxContextHash(txRequest.txContext).toBuffer(), ], @@ -300,20 +299,6 @@ export function computeTxHash(txRequest: TxRequest): Fr { ); } -function computeFunctionDataHash(functionData: FunctionData): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - functionData.selector.toBuffer(32), - new Fr(functionData.isInternal).toBuffer(), - new Fr(functionData.isPrivate).toBuffer(), - new Fr(functionData.isConstructor).toBuffer(), - ], - GeneratorIndex.FUNCTION_DATA, - ), - ); -} - function computeTxContextHash(txContext: TxContext): Fr { return Fr.fromBuffer( pedersenHash( @@ -346,24 +331,6 @@ function computeContractDeploymentDataHash(data: ContractDeploymentData): Fr { ); } -/** - * Computes a call stack item hash. - * @param callStackItem - The call stack item. - * @returns The call stack item hash. - */ -export function computePrivateCallStackItemHash(callStackItem: PrivateCallStackItem): Fr { - return Fr.fromBuffer( - pedersenHash( - [ - callStackItem.contractAddress.toBuffer(), - computeFunctionDataHash(callStackItem.functionData).toBuffer(), - callStackItem.publicInputs.hash().toBuffer(), - ], - GeneratorIndex.CALL_STACK_ITEM, - ), - ); -} - export function computeCommitmentsHash(input: SideEffect) { return pedersenHash([input.value.toBuffer(), input.counter.toBuffer()], GeneratorIndex.SIDE_EFFECT); } @@ -395,7 +362,7 @@ export function computePublicCallStackItemHash({ return Fr.fromBuffer( pedersenHash( - [contractAddress.toBuffer(), computeFunctionDataHash(functionData).toBuffer(), publicInputs.hash().toBuffer()], + [contractAddress, functionData.hash(), publicInputs.hash()].map(f => f.toBuffer()), GeneratorIndex.CALL_STACK_ITEM, ), ); diff --git a/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/index.ts b/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/index.ts index 662d561f3f2..e6c7cd56183 100644 --- a/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/index.ts +++ b/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/index.ts @@ -2,7 +2,8 @@ import { BarretenbergSync } from '@aztec/bb.js'; import { Point } from '@aztec/foundation/fields'; import { numToUInt32BE } from '@aztec/foundation/serialize'; -import { GrumpkinPrivateKey, PublicKey } from '../../../types/index.js'; +import { GrumpkinPrivateKey } from '../../../types/grumpkin_private_key.js'; +import { PublicKey } from '../../../types/public_key.js'; import { SchnorrSignature } from './signature.js'; export * from './signature.js'; diff --git a/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/signature.ts b/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/signature.ts index c753a847051..4ed9af1f607 100644 --- a/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/signature.ts +++ b/yarn-project/circuits.js/src/barretenberg/crypto/schnorr/signature.ts @@ -2,7 +2,7 @@ import { randomBytes } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, mapTuple } from '@aztec/foundation/serialize'; -import { Signature } from '../index.js'; +import { Signature } from '../signature/index.js'; /** * Schnorr signature used for transactions. diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 6aeeebb163b..27647730b03 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -19,11 +19,13 @@ export const MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; export const MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; export const MAX_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_NEW_CONTRACTS_PER_TX = 1; -export const MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX = 4; export const MAX_READ_REQUESTS_PER_TX = 128; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; export const NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; export const NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; +export const MAX_NEW_COMMITMENTS_PER_TX_META = 8; +export const MAX_NEW_NULLIFIERS_PER_TX_META = 8; +export const MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META = 2; export const NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP = 16; export const VK_TREE_HEIGHT = 3; export const FUNCTION_TREE_HEIGHT = 5; @@ -33,6 +35,7 @@ export const PUBLIC_DATA_TREE_HEIGHT = 40; export const NULLIFIER_TREE_HEIGHT = 20; export const L1_TO_L2_MSG_TREE_HEIGHT = 16; export const ROLLUP_VK_TREE_HEIGHT = 8; +export const ARTIFACT_FUNCTION_TREE_MAX_HEIGHT = 5; export const CONTRACT_SUBTREE_HEIGHT = 0; export const CONTRACT_SUBTREE_SIBLING_PATH_LENGTH = 16; export const NOTE_HASH_SUBTREE_HEIGHT = 6; @@ -48,7 +51,18 @@ export const FUNCTION_SELECTOR_NUM_BYTES = 4; export const MAPPING_SLOT_PEDERSEN_SEPARATOR = 4; export const NUM_FIELDS_PER_SHA256 = 2; export const ARGS_HASH_CHUNK_LENGTH = 32; -export const ARGS_HASH_CHUNK_COUNT = 16; +export const ARGS_HASH_CHUNK_COUNT = 32; +export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 1000; +export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; +export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; +export const REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = + 0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8n; +export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = + 0x1b70e95fde0b70adc30496b90a327af6a5e383e028e7a43211a07bcdn; +export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = + 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; +export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = + 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; export const L1_TO_L2_MESSAGE_LENGTH = 8; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; export const MAX_NOTE_FIELDS_LENGTH = 20; @@ -56,18 +70,18 @@ export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; export const VIEW_NOTE_ORACLE_RETURN_LENGTH = 212; export const CALL_CONTEXT_LENGTH = 8; -export const GLOBAL_VARIABLES_LENGTH = 4; +export const GLOBAL_VARIABLES_LENGTH = 6; export const PARTIAL_STATE_REFERENCE_LENGTH = 8; export const STATE_REFERENCE_LENGTH = 10; -export const HEADER_LENGTH = 18; +export const HEADER_LENGTH = 20; export const FUNCTION_DATA_LENGTH = 4; export const CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 204; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 207; +export const PRIVATE_CALL_STACK_ITEM_LENGTH = 212; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3; export const CONTRACT_STORAGE_READ_LENGTH = 2; -export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 201; +export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 203; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; -export const CALL_PRIVATE_FUNCTION_RETURN_SIZE = 210; export const COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP = 1024; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap index 1e861585d9d..122042ba049 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap @@ -88,41 +88,41 @@ AztecAddress { exports[`ContractAddress computeInitializationHash 1`] = ` Fr { - "asBigInt": 6008702290320255259549389675568071185910851926477784271985492188905918575237n, + "asBigInt": 11287307308183188516369033835241775664908452274022428157981236923904607656063n, "asBuffer": { "data": [ - 13, - 72, - 206, - 18, - 237, - 214, - 138, - 47, - 96, - 228, - 192, - 127, - 222, - 19, + 24, + 244, + 99, + 184, + 236, + 16, + 42, + 8, 156, - 23, - 220, + 101, + 39, + 106, + 125, + 199, + 236, + 87, + 43, + 9, + 28, + 163, + 148, + 181, 224, - 89, - 169, - 234, - 46, - 7, - 2, - 131, - 242, - 115, - 20, - 86, - 206, - 50, - 133, + 108, + 3, + 191, + 211, + 120, + 203, + 68, + 24, + 127, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap index 90d5d217ac8..acb681499c9 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap @@ -20,6 +20,7 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], + "packedBytecode": "0x000000028df71de50000002a171f8b08000000000000ffed9d097c1d55f5c7dfcb4bd2bcbcecfbd2242f4dd3360d69f3d28d5ad4b8518a0b1444aaa2a55bb0d8a6d8262c0a8a8ab8af7545140515dc57dc1744511064535054dc4041f6b52c65f99f3bef1ef2cbcdf425f3e7de97137ae7f339c99d7367eef99e73efdcb96fe6ceccb5b1582c1ecb2e0992fad8c485f307f5fffea7b7642c96d5ef92333e43380b66086762867016ce10cea219c2593c433867cd10ce9219c2999c219ca5338433354338cb660867f90ce1ac98219c953384b36a867056cf10ce9a19c2593b4338eb2c72b60027ffb66bd0ff1bf5ff26fdbf59ffe77d5af5ffd9fa7f9bf6b550afb7937490a4493a751e07660e4917c95c926e927924f3491690f4902c24e9253980a48f6411c962bdbffa813840b2846429c93292e5242b480e245949f22c92552407913c9be43924cfd5717b1ec9f3495e40f2429217911c4cb29ae4109235248792bc98e425242f257919c961248793acd5bea4b52f47901c49f27292a3485e417234c93a925792bc8ae4d524c790bc86e4b524eb498e25d940b2916413c966922d244324c791bc8e642bc9f124af27d946b29d64986407c909246f3062be936417c908c9a8c17922c9492427939c42f2469237919c4a721ac99b49de42723ac95b49de46f276923348de417226c93b49de45f26e92f790bc97e47d24ef27f900c907493e44f261928f90ec26f928c9c762e3ebffe3249f20f924c9a748ce22f934c9d9249f21f92cc939249f23f93cc9b924e7917c81e48b245f22399fe402922f937c85e4ab245f23f93ac93748be49f22d926f937c87e4bb24df23b990e4fb243f20f921c98f487e4cf213929f92fc8ce4e724bf20b988e497241793fc8ae4d72497685f0ab42fbf21f9ada1bb94e4329dfe9dfe7fb9fe7f85feff7bfdff4afdff2afdff6afdff1afdff5ac55f9d4dab31b3790d46e9f8988d838e8fdf02d0f1b19c001d1fd785a0e363bc08747cbc17838e8ffd59a06bd3e912d0b5439aff77e87429e8d23a9d025da74e97816e8e4e9783ae4ba72b403757a72b41d7add355a09ba7d3d5a09bafd335a05ba0d3b5a0ebd1e93afd9fe3a39641fdbfff692eaa4ccbe7917ec5ce6da31efce1b6d1003a6e1b8da0e3b6d1043af6bd1974dc365a40c76da31574dc3666838edb461be8b86d609be2b6d1013a6e1b69d071dbe8041db78d39a0e3b6d1053a6e1b7341c76da31b74dc36e6818edbc67cd071cc17808e63ce6d4ac5f810c8e7058f69bc3ecb3acec7633a0165b28ef3f198e67c3ca6391f8f69cce7ff9c8fc734e7e331cdf978fc723e1eab5caf785cf23e780c72bd623be672b0cd72bd62fbe4b2b12d72bd625b647bd816b95eb12d3203b645aed734e8980bdb221f4bd8169915fbb762286b50ffef7f7a4b06fb645ee2c6fa20a4d3fa7f31f86089a53f052c9d60a7cbae9d25782e998acf5dc0d26dd9673c5f4d85a51b58e6d96509aec9ceb75b6650a71c6bec43d9ce1cf06781657fe26087cbe575b695021df6e70b42f87aecf20dc4c10e97cbeb3dc0c7ba79ee62d58f7d1397adce131bc066dab24de53f1fe77cdf8219d85602b639b27a8c6b8bd695423e8e2d797fec53bb0d9d8b63280e76b85c5e9f077cdca774e7976f60aa7c730d3e077d5f10abb9064b985dcbc75d681d711bea716cd7ec8fba0cbbf8bb84975ce783f9c06bbbff54652eb45b6670ccf702f320d8c0f3ec010e62df0bf18c830dd627207d466c6c3900d269fd9f99d5b1d213b21da6e719fba420bfc7b1cf0b816310d6d996ea4b4f0106cb6d3ea8ef1e8381d7bb40bf30245e780ee4fc06d0717fdf0dba394619f85b1dfb55cbed3a93cb4fac77d6e16fc285217cbd76f90672b5855ee063dd02c7b1dad7b867e17e6cd7f6b187e5abe39c8f13b69380fc8e82b1edce0626cbbfbd06a2fedec17342da2a4ba63feaefc034b058feed1b9c6b3bec96d9efba4dc5207ecc8e7d089edb5c1c531d463df13af27956cfea593dab67f5ac9ed5b37ad6fd9b55b1cc3538f11ed85c017c61f7c06cff36c0fb8e5cb6faed7727d89c63d56626b81664fe9e33ef7d26609b2781eb5e9d2e857cbc9fd469e8ecff5eccd61fdbe172793d0d7cec0bd69feddf8bf1d8f8dfae83cf68bb039bec1f03997e35cf00e71099c75d5affc7b951ac536d724ec198bf768f95ec7d79bc3eaa965cd726e6388b7df61e6e97111bfbf531d08ff3160b62e3fb870eb06be99a468613786d94e3c71c61d7ca4a754594dbe5798a6b2af7855ddd9bc16bd8e9d8d83543b685d7ab795bf39e4e3a36f13e09de5ba9d1f153c7d085f1b1fd2cb7db81a8d7f7b06ddbadd3817e9ce7381516ac67cbe77e27f7f51cdcb308ae35e6baf786f7d1b0fd4dc77d34cfea593dab67f5ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea593dab679d49ac389f3eadffef6bbefa74f1b10eef0fd9beb68dcfe372d9eadec57970ef226dd5e6c0b867e3b8fc66a32ef0d9b81be19ecaf93a5d0af961731db0fe5cdcc3dad75c07b6550abe60fdd9bedf81f715b9dc67aeddecbd72bbc7c0c053f7cab93d99c71d3eab633ed386f7f9707e04cedf481bbae9aa0f3c66d2a0e334ce5fb11be38c8b7b68c17b750f807a60dff09937cebf08fa908be3637563f6172aff9a907c5ee2c6fa20a4f13efb22bbbe067de662287f106ca0dd7ebb763368371e1bffce23d627207d3504085f1ac6f16566d5eefa42b6c37487b14f0af2fb1cfbbc083806619d6da9767209b4a96be07c69fb7c83fe625c9a202e9c9f86b8d83ede948be6f88e19f039bbb906278eabb00fec73c0b7af71551ff099733c70be20f627385f306d9575fc18c89c0f9406bb96ce13e3e603e1fc8bced8c4770c24609b9b74bb56f381cc714f1af66d8632f33187c93c37e31ca65b81d9cf610a9fc364cecdc5394cf740bfd65a904def6bbc2de5f9631cc7a0df3dfbf01bdfc1e0a29f64ae228303c726bccda3d05ed5827dec3cfd1fc770e66f45fbe38d8160bcb6d86a99d9f3189e3fd33a8de308ce8f178c6d97d0e924f8dc09e5d484e4f3926bbcb608e23760d7d7e0585d02e50f820db4bbd4aedd0cdae5f11adb607d02d2d50563f1583a967c2abeccacda5d26643b4c1f60ec9382fc8c639f07806310d6d9966a27c5d0a6b8cdb81887a0bf189766880be7e3b5b139c6f6aa3de3fb6599d7f67189637a2ed71ce3878dbdf1fc607f8c34f19984746ce27522bc7e857d025ebf72f17c09cf99c7e74be6388cc5fff75d76f8cc0d1feaaee6f47746e09b037cbc5f02f8e63ae08bf2ccc15ce0e3fdf0dd92f31cf07547e09b077cbc5f11f0d97e5f12bed76e2a7c61efa02b86ffb6c78838169d0a1ff6bbbcdf2ce0b37dcd5ff1f546e0c3fb00bc5f09f059bebe14f0f545e0c36b32bc5f12f86c5f9351652f8ec0d70f7cbc5f29f0591eef057c99087c3846ca409af96c8f9114df92087c4b8189f72b03bee50ef89645e05b0e7cbc5f39f01de8806f4504be03818ff7ab00be6739e05b1981ef59c0c7fb5502df410ef85645e03b08f878bf2ae07b8e03be6747e07b0ef0f17ed5c037e880efb911f806818ff7ab01bee73be07b5e04bee7031fef570b7c2f74c0f782087c2f043ede0fdf877fb003be1745e03b18f8783f3cff1ee2806f7504be43808ff76b01be43edf205cf43ae89c07728b0bcd42ecb52c5f2e2082c2f059697d865099e877c99dd32836b8387592e53957138c484e3c7ec29c83f0ce275b8e578c5c12697cbebc8e759f76f56c5b2c6e04cc2766b04f0b1ee250e5992068b5a72f575617c589747d8e50bce0b6b23f01d012c47596559125c373c3202cb51c0f272ab2cd9f3c22bec9619f4e147033ffbca7652908f757eb465dfe26093cbe575e4f3ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea593dab7d56c5b2d6e04cc2766b05f0b1eee50e5992068b5a72cd1309e3c3ba7ca55dbe604ecdba087caf049663acb264bf3df1aa082cc700cbabadb264e7d4bcc66e99c19c9ad7023ffbca7652908f75fe5acbbec5c12697cbebc8e7593dab67f5ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea593dab67f5ac338555b1ac333893b0dd3a017cac7bb54396a4c1a2965cd7d9c3f8b02e8fb5cb17dc93581f81ef5860d964972578ffc386082c9b8065a35d96e09ec466bb6506f724b6003ffbca7652908f75bec5b26f71b0c9e5f23af279d6fd9b55b1ac373893b0dd7a017cacdbe8902569b0a82557bf14c68775799c5dbea00f1f8ac0771cb01c6f95257b5ff97511588e0796ad5659b27df8ebed9619f4e1db809f7d653b29c8c73adf66d9b738d8e472797d9b3bbb81ffdb27f17f7b08c7f63cfa8f7c53653d6c06b1fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab8fab84e9d55b10c199c49d86e48001febb63a64491a2c6ac975ed3e8c0fdbdd0ebb7cc17d8ee1087c3b8065a75596ec3ba94f88c0b21358de6095257b9f6397dd3283ebfc23c0cfbeb29d14e4639d8f58f62d0e36b95c5e47be6722ebb619c4eadb801b56df063cab6f039ed5b701cfeadb8067f56dc0b3fa36e0597d1bf0acbe0d7856df063cab6f039ed5b701cfeadb8067f56dc0b3fa36e059a7bb0d289661833309db0d0be063dd1b1cb2240d16b5e49a2712c687edee44bb7cc19c9ad1087c2702cb290e584e8ac0720ab09c6c97259853f346bb65f6ab32de04fcec2bdb49413ed6f99b2cfb16079b5c2eaf23df4c61552ca3066712b61b15c0c7ba931db2240d16b5e43a7ec2f8b02e4fb3cb171cdfa746e03b0d584e77c0f2e6082ca703cb5becb2047dcd5bed9619f4356f037ef695eda4201febfc6d967d8b834d2e97d7916fa6b02a96530dce246c77aa003ed6bdc5214bd260514baee3278c0febf20c077c6f8fc07706f0bd3d84ef4c077cef88c07726f0f17ea5c0f72e077cef8cc0f72ee07b27a499ef3d0ef8de1d81ef3dc0c4fb9501dffb1cf0bd3702dffb808ff72b07be0f38e07b7f04be0f001fef57017c1f72c0f7c1087c1f023edeaf12f83ee280efc311f83e027cbc5f15f07dd401dfee087c1f053ede0ffbbf8f3be0fb5804be8f03dfc742f83ee980ef1311f83e097c9f08e13bcb01dfa722f09d057c9f0ae13bdb01dfa723f09d0d7cbc1f5ec3faac03becf44e0fb2cb09c6397a53f052ce7809dcf3bf0f973b1a9fbccf653b01ff29de780efdc087ce701dfb9217c5f74c0f785087c5f043ede0fdbf4f90ef8be1481ef7ce0e3fdb04ff8b203be0b22f07d19f82e08e1fbaa03beaf44e0fb2af07d2584efeb0ef8be1681efebc0f7b510be6f3ae0fb4604be6f02df3742f8beed80ef5b11f8be0d7cdf0ae1fbae03beef44e0fb2ef07d2784ef42077cdf8bc07721f07d2f84ef070ef8be1f81ef07c0f7fd10be1f39e0fb6104be1f01df0f43f87ee280efc711f87e027c3f0ee1fb9903be9f46e0fb19f0fd3484ef170ef87e1e81ef17c0f7f310be5f3ae0bb2802df2f81efa210be5f39e0bb3802dfaf80efe210be4b1cf0fd3a02df25c0c7fbe1f8efb70ef87e1381efb7c0c7fb61fc2eb3cb17dc73b93402df65c072855d96e05b03bf8bc07205b05c6e9725b8fff37bbb6506f77fae047ef695eda4201febfc4acbbec5c12697cbebc8e759f76f56c572a9c19984ed2e15c0c7bacb1db2240d16b5e4ea97c2f8b02eafb6cb17f4e15745e0bb1a58fe60956569f00e9e6b22b0fc0158aeb5ca92edc3ff68b7cca00fbf0ef8d957b693827cacf3eb2cfb16079b5c2eaf23df5459b7cd20561f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571f571fd7a9b32a96ab0cce246c7795003ed65deb902569b0a825d73ce7303e6c777fb2cb17cc09bf3e02df9f80e52f5659068239e17f8ec0f21760b9c12a4b764ef85fed9619cc09ff1bf0b3af6c2705f958e77fb3ec5b1c6c72b9bc8e7c5365dd3683587d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c7d5c9f9971552cd71b9c49d8ee7a017cacbbc1214bd260514baeebec617cd8eefe6e972fb827716304bebf03cbbfacb22c09ee49fc2302cbbf80e59f5659b2f724fe6db7cce09ec44dc0cfbeb29d14e4639ddf64d9b738d8e472791df99e89acdb6610ab6f036e587d1bf0acbe0d7856df063cab6f039ed5b701cfeadb8067f56dc0b3fa36e0597d1bf0acbe0d7856df063cab6f039ed5b701cfeadb80679dee36a0586e343893b0dd8d02f858f74f872c4983452db9e68984f161bbfb8f5dbe604ecdcd11f8fe032cb7da6509bedff7df082cb702cb2d7659823935ffb35b6630a7e636e0675fd94e0af2b1ce6fb3ec5b1c6c72b9bc8e7c9e75ff66552c371b9c49d8ee66017cacbbc5214bd260514bae7e298c0febf20ebb7c411f7e7b04be3b80e56ebb2c411f7e670496bb81e52ebb2c411f7e8fdd32833efc5ee0675fd94e0af2b1ceefb5ec5b1c6c72b9bc8e7c9e75ff66552cb71b9c49d8ee76017cacbbcb214bd260514bae7e298c0febf27ebb7c411f7e5f04befb81658f03960722b0ec019607edb2047df84376cb0cfaf087819f7d653b29c8c73a7fd8b26f71b0c9e5f23af2cd1456c5729fc19984edee13c0c7ba071db2240d16b5e43a7ec2f8b02e1f75c0f74804be4781ef9110bec71cf0ed8dc0f718f0ed0de17bc201dfe311f89e00bec743f878679b7c4fc6a6cec79929d80ff90a1cf0c5e353e72b003ede0ff90a1df02522f015025f2284afd8015f5104be62e02b0ae14bdae50bc60fb322f0b17dc552623956aacc52bb65f6ab32539663a6ca28832071fc4aa1ee383f05f12ab31caf38d8e472791df9a6ca5a1f9b5e56077607ca62d971cd2cc316df7341a6729d2e043d1f7b6ab542eb8af43a6f7f8ede2601dbac4bea32758c79e98218573888312e8390ae80fae6a54910cb6e412cad82584605b1ac17c4b24610cb0a412c6d8258ea05b1f40a62490862e910c4d22d8825238865b6209661412ca571392ced82e2b24e10cb4a412c4b04b1340862e913c4325f104bb320964e412c438258d60a62592d88a55110cb2a412ccb04b12c16c4d22388253ecd2cc9d8c46be049c82f85ed0a8c7dd5b5c10f568fe557697d019453ad758990b2aba0ec4a9dae8e4fdc176354e52046686710d6d956293054c7a79fa54710cb62412ccb04b1ac12c4d2288865b52096b582588604b1740a626916c4325f104b9f209606412c4b04b1ac14c4b24e104bbb20161edf4a6019161497d98258328258ba05b1740862490862e915c4522f88a54d10cb0a412c6b04b1ac17c4322a88a55510cb6e412c4d8258baf2c4c2d70ab9dc4a83653aedd6d8b51b3c13540b76f9da690dc49dedd70247bd5d8e60ee3472a8c5581d777db91e58ea2cd7852ab3c1729c55998d9663a6ca68822071fc983d05f98d10af26076db7c168bbbc8e7c5365c5b96ed3c1eaaafe9b2dd73fcfc7e658361b31c578b7e87421e86bc0dfd996fd55c5b5ea32798e3733b0ad046cf38ad2ecff726dbf15d8b9ffc1791e1d96db858a635b84fea70362d7eea0ff493be8e73bc121f6350dc71fe7b7826f9d0e8ebfb471fcf17a27b0f08273fcd30e58701984743a84a54910cb6e412cd85ea69d45505c4605b1ac17c4d224a8bdac111497158258da04b1d40b62e915c49210c4d22188a55b104b4610cb6c412cc38258da05b1ac13c4b25210cb12412c7d8258e60b626916c4d22988654810cb5a412cab05b1340a6259258865992096c582587a04b1c4a799655f73fc39bf09b6e36b7c6da09ba3d3eda02b08b1c1bf773a4157a8755c86bad67c56f5c4b231462eae69a29d4158675b38c77f4e7cfa597a04b12c16c4b24c10cb2a412c8d8258560b62592b886548104ba7209666412cf305b1f4096259228865a52096758258da05b10c0b62992d88252388a55b104b8720968420965e412cf58258da04b1ac10c4b246100b5f5790c0b25e505c4605b1b44a6211d45e760b8a4b932096ae1016cbd73407f03a242fc66ae8754ec5d26d9725f86e545704966e60996bb98e5499f3ec9619cc7b9e6fb94c55c6020812c78fd953903f1fe2b5c0419b9e171f5f4fbc8e7c9e75ff66c5b9d5cc9984ed3a05f0b16e2eb0d8ee0b94cf3c1ee0b2d5fd9b8da9319b96e7f52f55c561ff3d080c6c2b01db9c5935c635a4b94a211fef3db587d45f9b83fa6b37ea8fd7dbe0bcc9beb4034bbb03960e8345925ddbb1c73ae6c5581d776e6e0316dbcfd3a4806536d86971e0736b049f5b80c5f2f34d9914b034831dcbcf8405fd125fc36b827ee9d494b3fa0cfaa536a35f62067c3e8ab719867ee974e897da428e8356cbf18903935ad260b715fac3d690f669fb993765a72542fbc47663f799be4cd06e9a22b034008be56741330e9ec9ed77f06ced84e78d9f7ae613c6229c5f07f1aa75704ea937ce29bc8e7c9ed5b37a56cfea593dab67f5ac9e75ff66552cfcfb03e735f3762d02f85887ef7cb1fddb20785f466c7c3da9dfa6d7c16f66bbbfd333c1ef50fc3d970606b695806d8ea81ce3ba017e33371b7595845861fd3538a8bf46a3fe789d6de17d6dacbf46072c4d06cb33d7eec026fbc740a69fdfbfd36cf457669d2adb96dfdb155ca7ab8338aac5581d77eda1c661bfa4caacb6dcbfa832aac021f6b51afa39cec7f703b87c371d976bbe9b0e9fc52900966a072cb80c42ba3a8465b7209651412cad8258d60b62592388252388a55e104bb720964a412c49412c09412c3806996e96d982e2d22e886589209606412cf305b15409626916c4522a88a55010cb902096b58258960962e911c4522d88252588a548104baba0b15493a0b8ac10c4d22688a557104b8d20960e412c6582588a05b10c0b6259278865a520963e412cb582583a05b1940b6299258865b5209646412cab04b12c16c4522788a54b104b85209612412c2d8258e2d3ccb2aff733727e1d6c677eeb0bdfc588e5f13d0ede5efd4e3fb77a62d905b1896563399cc618553a8811da198475b685ef67ac8e4f3f4b8b209612412c158258ba04b1d40962592c886595209646412cab05b1cc12c4522e88a553104bad20963e412c2b05b1ac13c4322c88a558104b9920960e412c3582587a05b1b40962592188a549100bdf1796c05224282e29412cd582587a04b12c13c4b25610cb90209642412ca582589a05b1540962992f88a54110cb12412ced8258660b62691034964a088a4b52104ba520966e412cf58258328258d60862592f88a55510cba82096dd8258cc7bdf98afc6e57cbee27bdb09c83f54df4c50fff6f58cb80bbf70198c4de4ded733e2d3cd322a88a55510cb7a412c6b04b16404b1740b62a914c49214c49210c4d2e0f8dc168565b6a0b8b40b62592288a54110cb7c412c5582589a05b1940a622914c432248865ad20966582587a04b1540b624909622912c4d22a682cd524282e2b04b1b40962e915c4522388a543104b99209662412cc38258d60962592988a54f104bad20964e412ce58258660962592d88a55110cb2a412c8b05b1d40962e912c4522188a544104b8b2096f834b3ecebb96cce4f80ae42ebf07b7be53add00ba82101b5c4e05e8f89a1c97a17ecf5f503d91a10018ca42b8787fb4c776cae213f7751d73b43308eb784f9f19ca1c5f37980a4b8b209612412c158258ba04b1d40962592c886595209646412cab05b1cc12c4522e88a553104bad20963e412c2b05b1ac13c4322c88a558104b9920960e412c3582587a05b1b40962592188a549100bfff696c05224282e29412cd582587a04b12c13c4b25610cb90209642412ca582589a05b1540962992f88a54110cb12412ced8258660b62691034964a088a4b52104ba520966e412c19412c6b04b1ac17c4d22a88655410cb6e412c05064b29e4f335abe0f7a5d67582ae54ebba4097d4ba6ed09568dd7cd0cdd2ba1ed0156b5d2fe88ab4ae0f74855ab7187409adcb80ae40eb96802eae75cb40c737a35780ee499d5e09ba27747a15e81ed7e9d5a07b4ca7b95f50e793470d9daaf347747a50ffef7f7a4b50e76c87cbe5f547806faf4e3f0a3a4eaf05e6870d9d627ec801f3c30633af3f047cccff30e838bd0e98f7183ac5fca003e63d0633af3f087cccbf07749c5e0fcc0f183ac57cbf03e6070c665ebf1ff898ff01d0717a0898ef33748af95e07ccf719ccbc7e2ff031ff7da0e3f43030df63e814f3dd0e98ef319879fd6ee063fe7b40c7e95160becbd029e63b1d30df6530f3fa9dc0c7fc77818ed3bb1df3ed35f8f61a7caeec3e62d87d244f761f32ec3e9427bb0f1a761fcc93ddfb0dbbf7e7c9eebd86dd7bf364f76ec3eedd79b2bbbfb5e7e9ea37f6b7f63c5dfdc6741d47fe7c941fbbfe7c941fbb53398e6eb76b772009e5f31237d607217d3bb0dc613906aaccdbec96d9afcafc9fe5325519b7424c387ecc9e82fcff41bc6eb51caf38d8e472791df9660a6b1274f81c05e7a740778bd69582eebf5c0ee8fea37525a0bb59eb6681ee26f61d74ffd6ba22d0fd4beb1e07e67feaf463a0fb874eef05dddf75fa51d0dda8d38f80ee6f3afd30e8feaad30f81ee2f3abd077437e8f483a0fbb34e3f00ba3fe9f4fda0bb5ea7ef03dd753a7d2fe8fea8d3f780ee0f3a7d37e8aed5e93b41778d4edf01baab75fa7fa0bb4aa70b21f6576a5d0274bfd7ba02d05da17571d05d1e63e598ee775af524d8bd4ca79f00dda53a7d17e8f89aed6da0e3fb67d89e792ec32da0e3394bff051dcfd9fc0fe8789ef8cda0e367536e021ddf2bfb37e878dec2bf40c7f393fe093a9e9ff90fd095ebf4df41c7cfa1dc083abe2ff637d0f1bc80bf828ee722fd05743cfff106d0f19ceb3f838e9ff3f813e8f8fdc2d7838eefbb5f073a7efee08fa0e379747f001dcfabb81674fc3cd235a0e37b2957838eef255f053a9ec37825e8f8fef7ef41c7d7f6af005d5aa72f075da74eff0e747374fa32d0f13d006eafaafda876d564f9be4610336390906bccd004f7581aedb2f4a780a511ecd45bb533d0af8ae37bf5ead84fc7c6eab91eecd6d9b19be1842aae16caef040eb695806d5ea30fca72bd7dade578c7c16e918e03f3d4020f6fb341f3a87eb0b0ca593b08c6b14d11da64a3fd3a6394fe24c4642a2c75ceda6d764c6dbb0da8326b2c97a9caa88620996d2a05f93510af6a07f76c6be3e3eb89d791cfb37a56cfea593dab67f5ac9ed5b37a56cfea593dab67f5ac9ed5b37a56cfea59670aab62e1ebe7f81e45deae49001febf07e8bed6bdb78af8ecb56f72eeeab1cb3d960d566f6de12de8f480303db4ac03607548d71edd15ca590df04f5571f527f750eeaafdea83f5e675bf8ac2bd65fbd03960683e5996b776093fd6360a05fcd0908ee9f1bfd9559a778efb50e8e15becf17bcb746eb5ba04d3618bae9aa0f3c661a42da69b3b37e26e3e21e5af0d85d35d443a3716e49407e25f421d555637563f6172a3f1d92cf8bb13aeebe26deb7b6fc6c65d0675640f9836003ed963b68576c37ae856d54409c39ddc11362603b8cefb8776ac4276e87e97a639f14e45739f6b9d238962a0d56d54eeaa04da5e15ebfedf30dfa8b71e1f91829c8c7ef4bd638880b8eefd2c0500375d462f43b38aec23eb02a8fe3aaaa9071551df0b11fd89f5c971a6375390632e7d734d83f4f8c9b5f83f32f3a81a31e8e67de6640b76b35bfc61cf7a4615ffc7e673ee60499e7669c13b40298f33527a8dee88b3186aba09f381ec60a61e3d73a43e7803f83fc5c6e9dc18fe3026c2fb67f0b61dfc08bb13aee1c5bedb07f73d02705f37cf05c12d61f713ecff374307e08eabccaa8f32ae3fc1a33b6a90d193fd6859c7f2b2cf78d2ecee9aa8c32e8db1b8cf37902f20f87e3f508180bb2cf8d50ce86907c5e72b5631ccb953ae89f92c658b1343ed16e8983369634c68a4f3d870071e6f4b130562c8160717c4ba1ddf1b310b85d4948bb2d85e38af3538e7d2e358eab528355b593a3a04d6d80b1a2ede31cfdc5b8f0f93905f9f8bbb6c938aef1db1d782e7231d62e33e257661c9ba9d8c4f7c8e0b9d4fef82ccbd5688c75cc6b5478ed0cfb04bc7636dbc1f9b22d423f331beaaed92ecb52555c0b1cef836003bf2ddfe8a06e9a0cbb2d46df9c823835858c69da216838164a87ec638e35719c86e7463e5fb642793c4629884d1c63a925ec7a39fe9662ce6ab05365d8b17e0ece8c1fb71480cd0a606b358e49c551e6a0aecb8dfec17c9f213e9782bfcf4f4d8dc58cebb5138f5d43a7f8db1cf0b71bfcbcde0675da61b4cb6288af1d96ec3cfd287d07b62fdbfd982ab3c56e99fdf6fbb8951b5519f89c05c7af25e4dc89d74f9b1cb4a316a31db5849c9fedda1dd8acca689cc4ffc6108ec63cfadfe8cceef24daa8c8649fc6f08e168c8a3ff0dceec2e1f5265d44fe27f7d08477d1efd7777bf6945701eac9bc4ffba108eba3cfa5fb78fb14c2ed6866966b56f7769d057d74ee27f6d08476d1efdaf756637b35c95513389ff35211c3579f4bfc699dd0383d766564fe27fbee69feccbff6a6776335b54195593f85f15c2519547ffab9cd95d19b4ffca49fcaf0ce1a8cca3ff95ceecaedca0caa898c4ff8a108e8a3cfa5fe1cceec6e0f5bae593f85f1ec2519e47ffcb9dd9dd70a02aa36c12ffcb4238caf2e87f9933bb0341fda726f13f15c291caa3ff2967763707e39fd249fc2f0de128cda3ffa5eeec06e7bfe424fe2743389279f43fe9cceee6e0b75ac924fe97847094e4d1ff1267763706f53f6b12ff678570cccaa3ffb39cd91d0aaed5144fe27f710847711efd2f7666777950ff4593f85f14c2519447ff8b9cd95d129cff0a27f1bf3084a3308ffe173ab3bb65a92a233189ff89108e441efd4f38b3bb2138fe0b26f1bf2084a3208ffe1738b33b10fcfe8f4fe27f3c84239e47ffe3ceec2edf983590dbff5808472c8ffec7dcd90dfc7f3296dbffa7f281e3c958fefc675bf6ed6e0efaff2762b9fde77ce478228ffe3fe1ce6ed0ff3d1ecbed3fe723c7e379f4ff7167765706fddf63b1dcfe733e723c9647ff1f736677e30655c6de49fce77ce4d89b47fff73ab3bb3418ff3e3a89ff9c8f1c8fe6d17fe46b093957f13b47836f681afc8ad5f2f7ab96aa321fb6ecbf2a83df5bace6a1f0dc0eb69380fce5d563db1da8d349f099e7ada8fcd521f9bc18abe3e67170cc94af96bf4b15cc357d00ca1f041b68d7e5b7a5e25ad806eb13903e985fca1b1bff9e7d8e2f7e436b4fc876986e31f64941fe1ec73eefebdb046c4bb59355d0a6b8cdb838ced15f8c4b2bc485f3715e93ede34d156d7e2b82191e06964ea33f51c711b7d14ee0dbe3806f5fdfd0d8037cacc3f7a5b31fd89f6c84796d9d5a8fdf4d4cebf41c28a7dbd0293fe739f093ed70b9bc3e0ff8f8bdcdddf9e51b982adf5c834fb12cb01cab24d8e425571fbe0058e65b665165f6d82d339837b310f8d957b693827c7cee65a165dfe26093cbe575e4eb0961e5f7a9e377887b80d572cc02d6b906ebdc10bb7d798811f72b7d8eedf61a76bb0cbbea38c17a524baee3a417780fb0ccabca5c64b7cc60fcb4189807c14617e8fb1dc47e31c4330e36589f80f469307eea1f4b3e75ae616675acf4856c87e985c63e29c8ef73ecf322e0188475b6a5ceaf3b61cc64b9cd07f5dd6730f07a17e81785c4ab0fe2c5f9dda0e33100f6b1738c3292500e9e6b2db7eb4c2e3fb1de59d70b7c8b42f816dbe51bc8d51616031feb0e001617fda0c9c2e71eec071b8df805cf920157c23257b12ed76699f88d185e72f5e7c5f0bfc8328bfab68c1e4ac7768decd8b9e1b82d476cd9b019af54171a88058086690e3d7ec6a61074fc199b22d0f1feb340c7e594409e0bd7d1372eb7d0602c06365b76f17340bce4aafe59c062bb29aa18f3e78074f51fbd73ebc816acff228331acfe555ec2d88eebadd03233dae272799d6d29bff89346276cd8f4fae7ed3c6e74fb96e1915d1868b361c70d87d48295858d99b72b329cb5dc58964a6b2cfc0da74d1bb66d3b7c74e3b6ad9b0e1e1dde34b275c7705893e1886175857519b8edbeba8a2478c63a2eab0474d80d7144cc88590b493d94c9cd27a19d298a8d358992d8d827ba822988b16cfb549fd8524fcaaaa778d5884b85577d12ab0ecafdb9feaf6ca94f5ea953a0faa495fa8495fa6495ba3ca21efd53af4e518fe2aa21503a96fdf9a2860f6a48a57e42a96192fa59a77e3aab9fd26a88a486446ad8a14eedea34ab4eabead4af8682eadad600c9121235af40dd5b53f38b5790a87996ea5ecbb34856911c44f26c92e7903c57c7f77924cf277901c90b495e447230c96a924348d6901c4af262929790bc94e4652487911c4eb296e4089223495e4e7214c92b488e265947f24a925791bc9ae41892d790bc96643dc9b1b1ecb040dd0f55cf2fa9fb62eadec010c97124af23d94a723cc9eb49b6916c8f653f51bf83e404923790ec24d9453212cb7e0afe449293484e263985e48d246f223995e434923793bc85e47492b792bc8de4ed246790bc83e44c927792bc8be4dd24ef21792fc9fb48de4ff201920f927c88e4c3241f89653ff1fe51928f917c9ce413249f24f914c959249f26399be433249f253987e473249f273997e43c922f907c91e44b24e7935c40f26592af907c95e46b245f27f906c93749be45f26d92ef907c97e47b2417927c9fe407243f24f911c98f497e42f253929fc5b26df517241791fc92e462925f91fc9ae41292df90fc3696fd5cd965b1ece7cd2e8f653f87a63e93a63e9fa63eaba63eb7a63ec3a63ecfc607321ec43c758f7fa26f1819d9b2fd8491f4c88ef4f6d16d235b4fd8764afaa4ad23af4bef3871cbcea16d3b4ec29dfffd7476be45afcc9eb8f386cd9bf7bddf237a853f78b76678f39693d33b4647d23b86d21b778c0e6f1e776e3a5a7b7d905e3f327b724eefdab66324dd9f1ea6bfd403ef3869cbe64569ccdb452eec1a49ef1ad9b073243db473c7f6746611967b54a99b728fa97c1a31cd543d8d9d97574dbd42fe0f6b585bbcfe1603009b2d6c6f0000001c481f8b08000000000000ffed9d077815c7b5c7efd54582ab2b01a6096424ad2aa24b028c316084e9cd0df70a06516c40188471efbdf7de7bc1bdf7827b27cf7e71123f3bcdce4b9ec94b5e122771e2e49dd93b07fd19966bedc70cda0b67bfefcfee9edd9df39b3367677767579775b1582c1e4b4f09528fd8a6136f6fd4f3ba2d9bea2d9655e792339e259c3959c299c812ce0e59c2999b259c7959c2d9314b383b650967324b38f3b3843395259c0559c25998259c9db384b34b967076cd12ce1db284b35b967076b7c8590c9cfcccd453cf7be979919ef7d6f33e7acec7eea8e77d755d3be8f5125229a98ce4e96d1c98725205a9925445aa26d590fa916a49fd4903480349834883494348437519eae1ab81348c349c3482b41369246967d228d22ea4d1a431a4b1a45d49e374ecc69376234d204d244d224d264d214d254d234d27cd20cd24cd22ed4eda83b4a7ae8ba7ebb217696fd26cd23ea47d49fb91f6271d403a907410e960d221a4434987910e27cd21cd251d419a479a4f6a222d202d242d222d261d493a8ab484b494b48cd44c5a6ec4fc68d20ad24a528bc1b98a740c6935e958d271a4e34927904e249d443a99740ae954d269a4d3496790ce249d453a9b740ee95cd279a4f34917902e245d44ba987409e952d265a4cb495790ae8c6ddcfe5791ae265d43ba96741de97ad20da41b4937916e26dd42ba95741be976d21da43b497791ee26dd43ba97741fe97ed203a435a407490f911e263d427a94f418e971d213a427494f919e263d437a96f41ce979d20ba417492f915e26bd427a95f41a692de9755d971c5d9737486f1ab6b7486febe577f4fc5d3d7f4fcfdfd7f30ff4fc433dff48cf3fd6f375aabcc2f4b2ba1735c736948dcfd938d8f8fccd011b9fcb09b0f179dd016c7c8ee7828dcff73cb0f1b9df116c7df57227b095c032cf4bf5723ed8caf4720a6c9e5e2e005bb95e2e045b855eee0cb64abddc056c557ab92bd8aaf5f20e60abd1cbddc0d64f2f77d7738e859a1af5bc6e0b2755a6e56b469d62e73ce801f5e13ce80936ce835e60e33c28021bd7bd37d8380ffa808df3a0186c9c073b828df3a02fd8380f307f380f4ac1c679500636ce030f6c9c07e560e33ca8001be74125d8380faac0c679500d368e6f0dd838be9c3f2a9e93613b4f78aee27826db783b9eab0928936dbc1dcf55de8ee72a6fc77315b7f39cb7e3b9cadbf15ce5ed785ef2763c07b90df17ce363ba838ddb10f393cbc15ce436c4bce3b231c7b80d31c7d81fe618b721e61833608ef139e2818db930c7f81cc11c6356ce3155d73ce06dd4f3ba2d9beab1efe6296eac37c232fb572c7dedb2d4a580a52ff829b5eb67185e73da52e75260f12cd719af6b6d61f180a5dc2e8b3f865961b74cbf4d39d6786eb09f12a84fa5e5fac4c10f97cbebec2b05360ff82a03f8aaecf235c4c10f97cbeb55c0c7b67277b1aac3fe8acb56d789c3c1a7e5bea74ed59fcf731ee76706f695807d9614b672cdd3b67cd85e0c363e1efb6dcfb0b93887f0998acbe5f572e0e33ec5dbba7c0d6de52b33f81cf47d7eacca0c16f16bbdcdebb07c75eef0f9c27e12b0fdbb78eb7eab81a9d82e5343d86b303e5fdabd46d5d7e1b9d716960a6071710db6ddb73bb876f939550d31f1f41cafabbcbd0ae2556d395e99aea1c827acc22aacc22aacc22aacc22aacdb372b8e4b797abeb9719ff6e2db5ae33e3c268de33e6f834fcfaacf7a7fdca7d828bfc8688b04ecf353e0e2f7a238ee83633cc586cdc1f8713df273b9bc8eef2d790c0aeb6af939da67d9d160d976fd36cc536596592db3be4ebd6fc277d365463df03d4f1fc3a672f2fb786b7d3dab6ce1dfcf78b15616dbe348f87ec65d9fd45087e3f639b18dfb874af06b694ca39e1794df6a237eccc1be12b0cf577a5e6897670357a6f14287d74f3f0e55e0d78bb59e1bf82edbbc96abe36a80cb83f85543fc789ff57aaecea14be11cb23de61d767c0f73db6e9b36d4e1bbafb6b0603bdb7e3fe6227754993596cb5465f4839898399582ed987ffd2cc70bfb072e97d7914f5885555885555885555885555885555885555885555885555885555885355b58158b6770e2f8bf17013eb6e1fb21db63dbf8b75a5cb67a777132bcbba8b0ea33fd2e0cdf4778b14dff5e2c01fb3c03df6f9fae97f361bba7e7f8ad8307e5bb7887f5437fe3921fdbf4ef725cbcefc0f78a5ceeb6eb37fdaedcee39d0b0e15d39e79379dee1df2d151b367ccfa7dadcd376fc7ea3c2b0b5577be0395301365ec66f1cecc6b8dec53b34fff708fb413b70ddd84f02b6df007dc84df1d6b631fb0bb57d4dc0769ee2c67a232ce37bf6fe76ebeaf79903a0fc46f0817e07daf55b8f7ee35aec83ed09587e000234b07571437c9959e55d6dc07eb85c691c9382edb58eebdc1f381a619d7da93cb915726a0d5c2f6d5f6fb0be189722880b6faf80b8d83edf5415f1fece03861a60293138f1be0afbc05a077c9bbbafaa053ef31b0ffc5e10fb13fc5ed0e53d508e114b6c434bd7898dbe07c2ef2fca81837d25609f97745eabef81ccfb1e0f8eed0d656e8d6f98cc6b337ec3b41698e51ba6e06f98cc6f73f11ba6f7a05ffb16ee6d2ac02ffbaa326c0eea5d6fd6bb11d6d917dedb60bdab36536ffc2d0617fd2473e51a1c786fc2fb7c0af9aa26ec63f9fb53bc87339f15eddf6f34f8f76b03ac9699be8ee1f593db0bef2378fbe790835fc0fd18d7b902ca591fb09da74cf76bfd217e83edd6d53f578740f98de003fd0eb5ebb71efdf2fd1afb607b0296bf81000d6d5ddc105f6656793728603f5cee671c9382ed831cd779307034c23afb5279f20bc8a9f570bf66fb3e04eb8b71e90d71e1ed3836e619fbab7ce6f3c183f8d93e2ff19e9ecb35eff183eebdf1fa60ff1e29cd550e5c5e2cf87785d8560e5c387e65f9ef04eaf09bf962f089dfcc47e5378d70cc2227d6ca57e280af6f08be12e0e3e312c067f7ef21d27ca521f8f077f9f0ef2298afdc019f1782af1cf8f8b85ce0b33dbe14f61befa0df22ca83b9ed7b44bc176d0b1ff6bb7c5c47e0b33de68fbfafd8163e7c0fc0c775023ecbe34b3e5f6d083e1c93e1e392c0677b4c46953d2004df40e0e3e3f281cff2fd9ecf3728041fde230d8265e6b37d8fa4f88684e01b0a4c7c5c01f0d53be0ab8bb59daf1ef8f8b842e01be680af2104df30e0e3e33a03df08077cc343f08d003e3eae0bf08d74c0b75308be91c0c7c77505be510ef8760ec1370af8f8b81d806fb403be5d42f08d063e3eae1bf08d75c0372604df58e0e3e3f03786c739e0db3504df38e0e3e37a00df78077c8d21f8c6031fdbf1fa3bc101df6e21f826001f1fd707f826d9e5f3ff1e726208be49c032d52ecb70c5323904cb5460996297c5ff7bc86976cbf4c706a75b2e5395310362c2f163f6146c9f0ef19a61395e71f0c9e5f23af209ebf6cdaa58261a9c49d86f6204f8d836c5214bd2605153a6be2e880fdb72965d3effba303304df2c60d9d32acb307fdc70f7102c7b02cb1e5659d2d785bdec96e9f7e17b033fd795fda4603bb6f9de96eb16079f5c2eaf239fb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb00aabb0da67552c330dce24ec3733027c6cdbc3214bd2605153a6ef4482f8b02df7b1cbe77f53333b04df3ec0b2bf5596f4ff3db16f0896fd81653fab2ce96f6a0eb05ba6ff4dcd81c0cf75653f29d88e6d7ea0e5bac5c12797cbebc827acc22aacc22aacc22aacc22aacc22aacc22aacc22aacc22aacc22aacc29a2dac8a65b6c19984fd6647808f6dfb3964491a2c6aca34ce1ec4876d79b05d3eff9dc44121f80e0696c3ecb2f8bfff70480896c380e550bb2cfe3b89c3ed96e9bf939803fc5c57f69382edd8e6732cd72d0e3eb95c5e9f037661ddbe5915cb41066712f63b28027c6c3bd4214bd2605153a67e694e001fb6e51176f9fc3e7c6e08be2380a5c92a4bfabdf2bc102c4dc032df2a4bba0f5f60b74cbf0f5f08fc5c57f69382edd8e60b2dd72d0e3eb95c5e5fe8ceaf5fff453f50ff45011c8bb662fd91afadacd3b38855e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e22a7195b8b69d55b1cc353893b0dfdc08f0b16dbe4396a4c1a2a64c63f7417c987747dae5f3df732c0ec17724b02cb5ca92fe4deaa342b02c0596255659d2ef3996d92dd31fe76f067eae2bfb49c1766cf366cb758b834f2e97d7916f5b645d9845ac92036e5825078455724058250784557240582507845572405825078455724058250784557240582507845572405825078455724058db3b0714cb62833309fb2d8e001fdb963864491a2c6acaf49d48101fe6ddd176f9fc6f6a9687e03b1a585a1cb0ac08c1d2022c2bedb2f8dfd4acb25ba6ff4dcd31c0cf75653f29d88e6d7e8ce5bac5c12797cbebc8972dac8a65b9c19984fd9647808f6d2b1db2240d1635653a7f82f8b02d8fb5cbe79fdfab43f01d0b2c273860392e04cb09c072bc5d16bfaf39d16e997e5f7312f0735dd94f0ab6639b9f64b96e71f0c9e5f23af2650bab62596d702661bfd511e063dbf10e5992068b9a329d3f417cd896a738e03b3904df29c0777200df690ef84e0dc1771af0f171f9c0778603bed343f09d017ca7c332f39de580efcc107c6701131f57007ce738e03b3b04df39c0c7c71502df790ef8ce0dc1771ef0f1719d81ef02077ce787e0bb00f8f8b82ec0779103be0b43f05d047c7c5c57e0bbc401dfc521f82e013e3e0efbbfcb1cf05d1a82ef32e0bb3480ef0a077c9787e0bb02f82e0fe0bbca01df9521f8ae02be2b03f8ae71c0777508be6b808f8fc331aceb1cf05d1b82ef3a60b9de2e4b5d0a58ae073f373aa8f30db1b6d799fda7e038e4bbd901df4d21f86e06be9b02f86e75c0774b08be5b818f8fc39cbedd01df6d21f86e073e3e0efb843b1df0dd1182ef4ee0bb2380ef6e077c7785e0bb1bf8ee0ae0bbd701df3d21f8ee05be7b02f8ee77c0775f08befb81efbe00be350ef81e08c1b706f81e08e07bc801df8321f81e02be0703f81e71c0f77008be4780efe100bec71cf03d1a82ef31e07b3480ef09077c8f87e07b02f81e0fe07bca01df9321f89e02be2703f89e71c0f77408be6780efe900bee71cf03d1b82ef39e07b3680ef05077ccf87e07b01f89e0fe07bc901df8b21f85e02be1703f85e71c0f77208be57808f8fc3fbbfd71cf0bd1a82ef35e0e3e3307eafdbe5f3dfb9ac0dc1f73ab0bc6597c5ffbf06de08c1f216b0bc6997c57ffff3b6dd32fdf73fef003fd795fda4603bb6f93b96eb16079f5c2eaf239fb06edfac8a65adc19984fdd646808f6d6f3a64491a2c6acad42f05f1615bbe6797cfefc3df0dc1f71eb07c689565b8ff1b3cef8760f910583eb0ca92eec33fb25ba6df877f0cfc5c57f69382edd8e61f5bae5b1c7c72b9bc8e7c6d655d9845ac125789abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae12d7b6b32a96770dce24ecf76e04f8d8f6814396a4c1a2a64cdf3907f161defdc82e9fff4df8ba107c3f02964fadb234f8df84ff4708964f81e513ab2ce96fc2ffd36e9975aa8c1f033fd795fda4603bb6f98f2dd72d0e3eb95c5e47beb6b22ecc225689abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e2ba6dc655b1ac333893b0dfba08f0b1ed13872c4983454d99c6d983f830ef7e6297cf7f27f15908be9f00cbe7565986f9ef247e1a82e57360f9995596f43b89ffb25ba6ff4ee20be0e7bab29f146cc736ffc272dde2e093cbe575e4db1659176611abe4801b56c90161951c1056c90161951c1056c90161951c1056c90161951c1056c90161951c1056c90161951c1056c90161951c10d6f6ce01c5f299c19984fd3e8b001fdb7ee6902569b0a829d37722417c98773fb7cbe77f53f36508be9f03cbafecb2f8ff7fdf2f42b0fc0a587e6997c5ffa6e6d776cbf4bfa9f90af8b9aeec2705dbb1cdbfb25cb738f8e472791df98475fb66552c5f1a9c49d8efcb08f0b1ed970e5992068b9a32f54b417cd896bfb1cbe7f7e15f87e0fb0db0fcce2e8bdf87ff770896df01cb6fedb2f87df8ffd82dd3efc3bf017eae2bfb49c1766cf36f2cd72d0e3eb95c5e473e61ddbe5915cbd7066712f6fb3a027c6cfbad4396a4c1a2a64cfd52101fb6e5efedf2f97df8fa107cbf07963f3a60f9df102c7f04963fd865f1fbf0ffb35ba6df87ff09f8b9aeec2705dbb1cdff64b96e71f0c9e5f23af2650bab62596f702661bff511e063db1f1cb2240d1635653a7f82f8b02dffe280efcf21f8fe027c7f0ee0fbab03be6f43f0fd15f8be0de0fbbb03bebf85e0fb3bf0fd2d80ef1f0ef8be0bc1f70fe0fb2e80ef7b077cff0cc1f73df0fd3380efdf0ef8fe1582efdfc0f7af00be78dc3e9f0994898ffda76047e4eb6097cfbf7fc809c1c7fe154bc272ac5499b976cbac5365e6598e992aa3230489e3970b6dc7dbf3205e1d2dc72b0e3eb95c5e47beb6b2f68cb52fab03bf0d05b1f47d4d8ee18bdfb9205327bddc01ec7ceea9d524c74eaff3fed7eb7d12b0cfb0647a5ea863cc530ec438e920c63835c27212fb153df589104b518458ba4488a520422cc908b1e44588251121965e1162e91a2196c208b1e44788a56384583a4488a577845872e3d161e91ca1b8a422c4d229422cb9116289b7334b32b6e9f36c12b6e7c27e39c6b12a8ef716b66e4f697b0e9453a06d8980b2535076be5e2e886f7a2cc628e52046e8a711d6d9573e3014c4db9f2537422c9d22c4928a104be708b1e4c6a3c3d23b4271e91021968e1162c98f104b618458ba4688a5578458121162c98b104b32422c051162e9122196a208b1f489104bce5662e1fb7e2e37df60694fbf8576fdfadfea7406bffc1c54087167ff9d81a3b35d8e119b7bdfd2c5419c716a8465f6b5b9f72dedcd52142116ccc9f666e912a1b814448825192196bc08b12422c4d22b422c5d23c452182196fc08b1748c104b8708b1f48e104be708b1a422c4d229422cb9116289b733cbe6deb7f0767c4fd2d5781650b61d8ce7147c2f833eb89cae60e33e84cb50edf278e1a60cf8fea65b00171f8ffed84fb7f8a6c7ba8e7937e379b69bc187ef6fba39be976e0b4b6e84583a458825152196ce1162e91d21960e1162e9182196fc08b1144688a56b84587a458825112196bc08b12423c4521021962e1162e17bcf28b01445282e7d22c49213c0d2c32ecb707c66e0c958dde819a807b074b71c1755664fbb65fa7f1bd5cb7299aa8c220812c78fd953b0bd17c4abc8411ef58c6fdc4ebc8e7cc2ba7db32abfbdadfa4dff7f833d43f41bbd1dc64095d9c7c1395e0c15e2baf681f62d0e68df6207eddbc7685f5e473e61155661155661155661155661155661155661155661155661155661155661155661155661155661155661155661b5cfaafcee68d56f83ffcd05fa5593b1bac1570cfcbb88812ab3afdd32fd6f2e4aa0425cd7bed0be2501ed5be2a07dfb1aedcbebc827acc22aacc22aacc22aacc22aacc22aacc22aacc22aacc22aacc22aacc29a2dacca6fa95dbffedf17a35f3519ab1b8d59973a8c812ab3cc6e99fe98b50715e2ba9641fb7a01edeb3968df32a37d791df98475fb66557ecbadfa4dbf972a0b718e973b8c812ab3c2c1395e0915e2ba5640fb5606b46fa583f6ad30da97d72bddf9f5eb5ff503f5af0ae0a8da8af547beb6b2f6ca225689abc455e22a7195b84a5c25ae125789abc455e22a7195b84a5c25ae125789abc455e2da7656e5b7daaadff46f62a25f3519ab1b8d83573b8c812ab3c66e99fe38703fa810d7b506dab75f402ef673d0be3546fbf23af26d8bac9512d7ed9e55724058250784557240582507845572405825078455724058250784557240582507845572405825078455724058250784b5bd7340f9adb5ebb72169f85593b1bac1570cfcbb88812ab3bfdd32fd6f2e064085b8aefda17d0704e4e20007eddbdf685f5e47be6c61557e073ac8c5fe217271a0c318a8320739c8c5c15021aeeb2068dfc101ed3bd841fb0e32da97d7912f5b589360cb89b5da787b026c43b4ad03d8866a5b2ed8eaa04e6cabd7b68e606bd0b64e601b065c3c1fae6d7dc03642dbbac0fe3be9e5ee601ba9977b826d67bd5c04b651ec036cbbe8e562b08dd6cb7dc136462f97806dac5e2e03dbae7ad903db38bd5c01b646bd5c05b6f1c6b555d97633ae71ca36c1e8f7946da2d1ff28db2423ff946db25ece8fb5daa640ceb26daab615806d9ab615826dbab67506db0c6e37b0cdd4b6ae609b15c0c7f939086c9c9f98cf9c9f43c0c6f939146c9c9f7560e3fcac071be76703d8383f315f396ec3c1c6711b01368edb4e60e3b88d041bc76d67b071dc46818de3b60bd876d0b6d160eba66d63c0d65ddbc682ad87b6ed0ab69eda360e6cbdb4ad116c45da361e6cbdb56d37b0f1b93c016cc5da36116c3b6adb24b0f5d5b6c9602bd1b629602bd5b6a9602bd3b66960f3b46d3ad8cab56d06d82ab46d26d82ab56d16f46ff9c0c875ca87ba302bfa665b1ef86ed4f3ba2d9bfc54663f5c2eaf97031fc7cbdbba7c0d6de52b33f8fcdf9bb0cb528f6dcf53dc586f84e54a60a9b0cce27f9b6db74cff3eaa1af8b9aeec2705db7b42ddaa2dd72d0e3eb95c5e47beaa0056ee77544e78c67e0e6296fe6d1b83b52cc06fed568811f72bb58efdd6187e4b0dbfea3cc1765253a6f3a40678fb59e6f59f7ded96e9df120c00e646f0510af68196eb827ee35aec83ed0958be9a6f1c603f35f1b58699d5b9521bb01f2e571bc7a4607bade33af7078e4658675fea9eee82c25606cb39efb777adc1c0eba560ef1f10af5a88176ff7c0c6f700d8c796186524a11cbcd65aceebfa4cf5c476675b0df0f50fe01b6097af21532e0c003eb6f5031617fda0c9c2d71eec077b19f153b97a3870252c73e5c55a9f5d6c9589cf4d3c65eacff3609e6b99453d6ff173d3ca96e615731736eddd34777e1cb03a1888398086cb387cc18f76387cc18f76387cc1c7e3500597d309b6a9657ea46a5abab865df654dcbe6ad386e794bd3fc99cd0b3178b906cde628912e0fbc35ea79dd964d0df8d0cb53a646ee042c1dedb2f8499cb45ba67f739b0ffc3800a5a6146ccf857df22dd72d0e3eb95c5ecf77e7b78eeb98a9fea9008ed456ac3f0e24250338793b9e7d3830c9f384519edadfcc656b15ea0165c635900250276b6eacf504e9146b1d0952606aa447ddb4a8911c3572a3466ad4c88cea36ba43992fe9b9f2a39ebad415458da4a891133552a2ee20d41d9dbafb57575f7547a29e40bc58faa9483d79aa27517587a1ee28d4555b5d19d5554a5d95d49553dd490d220d260d210d557121d5931a48c348c34923483b91469276268d22ed421a4d1a431a4bda95344ec7773c6937d204d244d224d264d214d254d234d274d20cd24cd22cd2eea43d487b92f622ed4d9a4dda87b42f693fd2fea4034807920e221d4c3a847428e9b058fa0a3b8734977404691e693ea989b480b490b488b4987424e928d212d252d23252336939e968d20ad24a520b6915e918d26ad2b1a4e348c7934e209d483a897432e914d2a9a4d348a793ce209d493a8b7436e91cd2b9a4f348e7932e205d48ba887431e912d2a5a4cb489793ae205d49ba8a7435e91ad2b5a4eb48d7936e20dd48ba897433e916d2ada4db48b793ee20dd49ba8b7437e91ed2bda4fb48f7931e20ad213d487a88f430e911d2a3a4c7488f939e203d497a8af434e919d2b3a4e748cf935e20bd184be7ebcba45748af925e23ad25bd4e7a83f426e92dd2dba47748ef92de23bd4ffa80f421e923d2c7a475b1d6ce184fe05feb393ff5cf6d69695ababcc56b69f696ae5ad2b278f992e3bcd58b5b1679cdc734ad58b0a479351efc627c0b0e7e8dc7f8373d78eefcf99b3fee13bdc267f6b465f39b8ef59a57b578cd0bbc239a572d9bbf12776fd0ddd918bd3e3b7dabe3ad5cd2dce2d579cbe8dfb94bc845d3fc211e6e5b495558d9e2ad6c99bba2c55bb0a279a9573fe4ff01285f3937f75f0200", "privateFunctions": [ { "selector": { @@ -43,7 +44,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "packedBytecode": "0x", - "id": "0x034c098fd12d17ec1ecb116e91d01ddc76748569790835f91c866f3e8ec8466a" + "id": "0x09ad0dad993129857629f13ec2f3463d0c15615bd35266d0fb26c8793c6ee050", + "privateFunctionsRoot": "0x05fa82a96814b6294d557d507151f7ccc12f70522ec4d9d0395a90e87e8087c6", + "publicBytecodeCommitment": "0x05a06c2ee54a742daa2fa43a111c03335df68ff89fd8e7ba938ca2efb225c885" }" `; diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts index e5584ba3904..c3b04e7feaa 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.test.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.test.ts @@ -1,11 +1,11 @@ import { getSampleContractArtifact } from '../tests/fixtures.js'; -import { getArtifactHash } from './artifact_hash.js'; +import { computeArtifactHash } from './artifact_hash.js'; describe('ArtifactHash', () => { it('calculates the artifact hash', () => { const artifact = getSampleContractArtifact(); - expect(getArtifactHash(artifact).toString()).toMatchInlineSnapshot( - `"0x1cd31b12181cf7516720f4675ffea13c8c538dc4875232776adb8bbe8364ed5c"`, + expect(computeArtifactHash(artifact).toString()).toMatchInlineSnapshot( + `"0x242a46b1aa0ed341fe71f1068a1289cdbb01fbef14e2250783333cc0607db940"`, ); }); }); diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.ts b/yarn-project/circuits.js/src/contract/artifact_hash.ts index 88a0c122d43..e51852a8aa6 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.ts @@ -3,6 +3,7 @@ import { sha256 } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { numToUInt8 } from '@aztec/foundation/serialize'; +import { MerkleTree } from '../merkle/merkle_tree.js'; import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; const VERSION = 1; @@ -29,39 +30,49 @@ const VERSION = 1; * ``` * @param artifact - Artifact to calculate the hash for. */ -export function getArtifactHash(artifact: ContractArtifact): Fr { - const privateFunctionRoot = getFunctionRoot(artifact, FunctionType.SECRET); - const unconstrainedFunctionRoot = getFunctionRoot(artifact, FunctionType.OPEN); - const metadataHash = getArtifactMetadataHash(artifact); +export function computeArtifactHash(artifact: ContractArtifact): Fr { + const privateFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.SECRET); + const unconstrainedFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.UNCONSTRAINED); + const metadataHash = computeArtifactMetadataHash(artifact); const preimage = [numToUInt8(VERSION), privateFunctionRoot, unconstrainedFunctionRoot, metadataHash]; + // TODO(@spalladino) Reducing sha256 to a field may have security implications. Validate this with crypto team. return Fr.fromBufferReduce(sha256(Buffer.concat(preimage))); } -function getArtifactMetadataHash(artifact: ContractArtifact) { - const metadata = { name: artifact.name, events: artifact.events }; // TODO(@spalladino): Should we use the sorted event selectors instead? They'd need to be unique for that. +export function computeArtifactMetadataHash(artifact: ContractArtifact) { + // TODO(@spalladino): Should we use the sorted event selectors instead? They'd need to be unique for that. + const metadata = { name: artifact.name, events: artifact.events }; return sha256(Buffer.from(JSON.stringify(metadata), 'utf-8')); } -type FunctionArtifactWithSelector = FunctionArtifact & { selector: FunctionSelector }; +export function computeArtifactFunctionTreeRoot(artifact: ContractArtifact, fnType: FunctionType) { + return computeArtifactFunctionTree(artifact, fnType)?.root ?? Fr.ZERO.toBuffer(); +} -function getFunctionRoot(artifact: ContractArtifact, fnType: FunctionType) { - const leaves = getFunctionLeaves(artifact, fnType); +export function computeArtifactFunctionTree(artifact: ContractArtifact, fnType: FunctionType): MerkleTree | undefined { + const leaves = computeFunctionLeaves(artifact, fnType); + // TODO(@spalladino) Consider implementing a null-object for empty trees + if (leaves.length === 0) { + return undefined; + } const height = Math.ceil(Math.log2(leaves.length)); const calculator = new MerkleTreeCalculator(height, Buffer.alloc(32), (l, r) => sha256(Buffer.concat([l, r]))); - return calculator.computeTreeRoot(leaves); + return calculator.computeTree(leaves); } -function getFunctionLeaves(artifact: ContractArtifact, fnType: FunctionType) { +function computeFunctionLeaves(artifact: ContractArtifact, fnType: FunctionType) { return artifact.functions .filter(f => f.functionType === fnType) .map(f => ({ ...f, selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters) })) .sort((a, b) => a.selector.value - b.selector.value) - .map(getFunctionArtifactHash); + .map(computeFunctionArtifactHash); } -function getFunctionArtifactHash(fn: FunctionArtifactWithSelector): Buffer { +export function computeFunctionArtifactHash(fn: FunctionArtifact & { selector?: FunctionSelector }): Buffer { + const selector = + (fn as { selector: FunctionSelector }).selector ?? FunctionSelector.fromNameAndParameters(fn.name, fn.parameters); const bytecodeHash = sha256(Buffer.from(fn.bytecode, 'hex')); const metadata = JSON.stringify(fn.returnTypes); const metadataHash = sha256(Buffer.from(metadata, 'utf8')); - return sha256(Buffer.concat([numToUInt8(VERSION), fn.selector.toBuffer(), metadataHash, bytecodeHash])); + return sha256(Buffer.concat([numToUInt8(VERSION), selector.toBuffer(), metadataHash, bytecodeHash])); } diff --git a/yarn-project/circuits.js/src/contract/contract_address.ts b/yarn-project/circuits.js/src/contract/contract_address.ts index 36be5b26e02..b567aafc5c8 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.ts @@ -1,10 +1,12 @@ import { FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { ContractInstance } from '@aztec/types/contracts'; import { computeVarArgsHash } from '../abis/abis.js'; -import { AztecAddress, GeneratorIndex, PublicKey } from '../index.js'; +import { GeneratorIndex } from '../constants.gen.js'; +import { PublicKey } from '../types/public_key.js'; // TODO(@spalladino): Review all generator indices in this file diff --git a/yarn-project/circuits.js/src/contract/contract_class.ts b/yarn-project/circuits.js/src/contract/contract_class.ts index 936596d6912..9b39db4d094 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.ts @@ -2,8 +2,9 @@ import { ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundat import { Fr } from '@aztec/foundation/fields'; import { ContractClass, ContractClassWithId } from '@aztec/types/contracts'; -import { getArtifactHash } from './artifact_hash.js'; -import { computeContractClassId } from './contract_class_id.js'; +import { computeArtifactHash } from './artifact_hash.js'; +import { ContractClassIdPreimage, computeContractClassIdWithPreimage } from './contract_class_id.js'; +import { packBytecode } from './public_bytecode.js'; /** Contract artifact including its artifact hash */ type ContractArtifactWithHash = ContractArtifact & { artifactHash: Fr }; @@ -11,18 +12,22 @@ type ContractArtifactWithHash = ContractArtifact & { artifactHash: Fr }; /** Creates a ContractClass from a contract compilation artifact. */ export function getContractClassFromArtifact( artifact: ContractArtifact | ContractArtifactWithHash, -): ContractClassWithId { - const artifactHash = (artifact as ContractArtifactWithHash).artifactHash ?? getArtifactHash(artifact); +): ContractClassWithId & ContractClassIdPreimage { + const artifactHash = 'artifactHash' in artifact ? artifact.artifactHash : computeArtifactHash(artifact); + const publicFunctions: ContractClass['publicFunctions'] = artifact.functions + .filter(f => f.functionType === FunctionType.OPEN) + .map(f => ({ + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), + bytecode: Buffer.from(f.bytecode, 'base64'), + isInternal: f.isInternal, + })); + const packedBytecode = packBytecode(publicFunctions); + const contractClass: ContractClass = { version: 1, - artifactHash: artifactHash, - publicFunctions: artifact.functions - .filter(f => f.functionType === FunctionType.OPEN) - .map(f => ({ - selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), - bytecode: Buffer.from(f.bytecode, 'base64'), - isInternal: f.isInternal, - })), + artifactHash, + publicFunctions, + packedBytecode, privateFunctions: artifact.functions .filter(f => f.functionType === FunctionType.SECRET) .map(f => ({ @@ -30,10 +35,8 @@ export function getContractClassFromArtifact( vkHash: getVerificationKeyHash(f.verificationKey!), isInternal: f.isInternal, })), - packedBytecode: Buffer.alloc(0), }; - const id = computeContractClassId(contractClass); - return { ...contractClass, id }; + return { ...contractClass, ...computeContractClassIdWithPreimage(contractClass) }; } /** diff --git a/yarn-project/circuits.js/src/contract/contract_class_id.ts b/yarn-project/circuits.js/src/contract/contract_class_id.ts index d6785002e09..2165225a37c 100644 --- a/yarn-project/circuits.js/src/contract/contract_class_id.ts +++ b/yarn-project/circuits.js/src/contract/contract_class_id.ts @@ -18,20 +18,36 @@ import { computePrivateFunctionsRoot } from './private_function.js'; * @param contractClass - Contract class. * @returns The identifier. */ -export function computeContractClassId(contractClass: ContractClass): Fr { - const { privateFunctionsRoot, publicBytecodeCommitment } = computeContractClassIdPreimage(contractClass); - return Fr.fromBuffer( +export function computeContractClassId(contractClass: ContractClass | ContractClassIdPreimage): Fr { + return computeContractClassIdWithPreimage(contractClass).id; +} + +/** Computes a contract class id and returns it along with its preimage. */ +export function computeContractClassIdWithPreimage( + contractClass: ContractClass | ContractClassIdPreimage, +): ContractClassIdPreimage & { id: Fr } { + const artifactHash = contractClass.artifactHash; + const privateFunctionsRoot = + 'privateFunctionsRoot' in contractClass + ? contractClass.privateFunctionsRoot + : computePrivateFunctionsRoot(contractClass.privateFunctions); + const publicBytecodeCommitment = + 'publicBytecodeCommitment' in contractClass + ? contractClass.publicBytecodeCommitment + : computePublicBytecodeCommitment(contractClass.packedBytecode); + const id = Fr.fromBuffer( pedersenHash( - [contractClass.artifactHash.toBuffer(), privateFunctionsRoot.toBuffer(), publicBytecodeCommitment.toBuffer()], + [artifactHash.toBuffer(), privateFunctionsRoot.toBuffer(), publicBytecodeCommitment.toBuffer()], GeneratorIndex.CONTRACT_LEAF, // TODO(@spalladino): Review all generator indices in this file ), ); + return { id, artifactHash, privateFunctionsRoot, publicBytecodeCommitment }; } /** Returns the preimage of a contract class id given a contract class. */ export function computeContractClassIdPreimage(contractClass: ContractClass): ContractClassIdPreimage { const privateFunctionsRoot = computePrivateFunctionsRoot(contractClass.privateFunctions); - const publicBytecodeCommitment = computeBytecodeCommitment(contractClass.packedBytecode); + const publicBytecodeCommitment = computePublicBytecodeCommitment(contractClass.packedBytecode); return { artifactHash: contractClass.artifactHash, privateFunctionsRoot, publicBytecodeCommitment }; } @@ -43,6 +59,6 @@ export type ContractClassIdPreimage = { }; // TODO(@spalladino): Replace with actual implementation -function computeBytecodeCommitment(bytecode: Buffer) { +export function computePublicBytecodeCommitment(bytecode: Buffer) { return Fr.fromBufferReduce(sha256(bytecode)); } diff --git a/yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts b/yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts new file mode 100644 index 00000000000..295f65c40c0 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts @@ -0,0 +1,18 @@ +import { getSampleContractClassRegisteredEventPayload } from '../tests/fixtures.js'; +import { computePublicBytecodeCommitment } from './contract_class_id.js'; +import { ContractClassRegisteredEvent } from './contract_class_registered_event.js'; + +describe('ContractClassRegisteredEvent', () => { + it('parses an event as emitted by the ContractClassRegisterer', () => { + const data = getSampleContractClassRegisteredEventPayload(); + const event = ContractClassRegisteredEvent.fromLogData(data); + expect(event.contractClassId.toString()).toEqual( + '0x1c9a43d08a1af21c35e4201262a49497a488b0686209370a70f2434af643b4f7', + ); + expect(event.artifactHash.toString()).toEqual('0x072dce903b1a299d6820eeed695480fe9ec46658b1101885816aed6dd86037f0'); + expect(event.packedPublicBytecode.length).toEqual(27090); + expect(computePublicBytecodeCommitment(event.packedPublicBytecode).toString()).toEqual( + '0x1d5c54998c08cee8ad4a8af5740f2e844fe6db3a5bb4b6382a48b2daeabeee3f', + ); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/contract_class_registered_event.ts b/yarn-project/circuits.js/src/contract/contract_class_registered_event.ts new file mode 100644 index 00000000000..d0acde29dac --- /dev/null +++ b/yarn-project/circuits.js/src/contract/contract_class_registered_event.ts @@ -0,0 +1,76 @@ +import { bufferFromFields } from '@aztec/foundation/abi'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader } from '@aztec/foundation/serialize'; +import { ContractClassPublic } from '@aztec/types/contracts'; + +import chunk from 'lodash.chunk'; + +import { REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE } from '../constants.gen.js'; +import { computeContractClassId, computePublicBytecodeCommitment } from './contract_class_id.js'; +import { unpackBytecode } from './public_bytecode.js'; + +/** Event emitted from the ContractClassRegisterer. */ +export class ContractClassRegisteredEvent { + constructor( + public readonly contractClassId: Fr, + public readonly version: number, + public readonly artifactHash: Fr, + public readonly privateFunctionsRoot: Fr, + public readonly packedPublicBytecode: Buffer, + ) {} + + static isContractClassRegisteredEvent(log: Buffer) { + return toBigIntBE(log.subarray(0, 32)) == REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE; + } + + static fromLogData(log: Buffer) { + if (!this.isContractClassRegisteredEvent(log)) { + const magicValue = REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE.toString(16); + throw new Error(`Log data for ContractClassRegisteredEvent is not prefixed with magic value 0x${magicValue}`); + } + const reader = new BufferReader(log.subarray(32)); + const contractClassId = reader.readObject(Fr); + const version = reader.readObject(Fr).toNumber(); + const artifactHash = reader.readObject(Fr); + const privateFunctionsRoot = reader.readObject(Fr); + const packedPublicBytecode = bufferFromFields( + chunk(reader.readToEnd(), Fr.SIZE_IN_BYTES).map(Buffer.from).map(Fr.fromBuffer), + ); + + return new ContractClassRegisteredEvent( + contractClassId, + version, + artifactHash, + privateFunctionsRoot, + packedPublicBytecode, + ); + } + + toContractClassPublic(): ContractClassPublic { + const computedClassId = computeContractClassId({ + artifactHash: this.artifactHash, + privateFunctionsRoot: this.privateFunctionsRoot, + publicBytecodeCommitment: computePublicBytecodeCommitment(this.packedPublicBytecode), + }); + + if (!computedClassId.equals(this.contractClassId)) { + throw new Error( + `Invalid contract class id: computed ${computedClassId.toString()} but event broadcasted ${this.contractClassId.toString()}`, + ); + } + + if (this.version !== 1) { + throw new Error(`Unexpected contract class version ${this.version}`); + } + + return { + id: this.contractClassId, + artifactHash: this.artifactHash, + packedBytecode: this.packedPublicBytecode, + privateFunctionsRoot: this.privateFunctionsRoot, + publicFunctions: unpackBytecode(this.packedPublicBytecode), + version: this.version, + }; + } +} diff --git a/yarn-project/circuits.js/src/contract/contract_instance.ts b/yarn-project/circuits.js/src/contract/contract_instance.ts index 6c57db21e37..d5af7c7db5d 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance.ts +++ b/yarn-project/circuits.js/src/contract/contract_instance.ts @@ -1,7 +1,11 @@ import { ContractArtifact } from '@aztec/foundation/abi'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr, Point } from '@aztec/foundation/fields'; import { ContractInstance, ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { EthAddress, Fr, Point, PublicKey, computeContractClassId, getContractClassFromArtifact } from '../index.js'; +import { getContractClassFromArtifact } from '../contract/contract_class.js'; +import { computeContractClassId } from '../contract/contract_class_id.js'; +import { PublicKey } from '../types/public_key.js'; import { computeContractAddressFromInstance, computeInitializationHash, diff --git a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts new file mode 100644 index 00000000000..c7081791b4c --- /dev/null +++ b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts @@ -0,0 +1,13 @@ +import { getSampleContractInstanceDeployedEventPayload } from '../tests/fixtures.js'; +import { ContractInstanceDeployedEvent } from './contract_instance_deployed_event.js'; + +describe('ContractInstanceDeployedEvent', () => { + it('parses an event as emitted by the ClassInstanceDeployer', () => { + const data = getSampleContractInstanceDeployedEventPayload(); + const event = ContractInstanceDeployedEvent.fromLogData(data); + expect(event.address.toString()).toEqual('0x173b1e288f0f29f945ffa7b4ec2b69393e32b78501d0f193288e4a886a9f6e18'); + expect(event.contractClassId.toString()).toEqual( + '0x0798434d6f2adf997c4fe3d14cb8468aa3cbf7a70d8c499c3c775fc8feff6796', + ); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts new file mode 100644 index 00000000000..45af7ba5187 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts @@ -0,0 +1,68 @@ +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader } from '@aztec/foundation/serialize'; +import { ContractInstanceWithAddress } from '@aztec/types/contracts'; + +import { DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../constants.gen.js'; +import { AztecAddress, EthAddress } from '../index.js'; + +/** Event emitted from the ContractInstanceDeployer. */ +export class ContractInstanceDeployedEvent { + constructor( + public readonly address: AztecAddress, + public readonly version: number, + public readonly salt: Fr, + public readonly contractClassId: Fr, + public readonly initializationHash: Fr, + public readonly portalContractAddress: EthAddress, + public readonly publicKeysHash: Fr, + public readonly universalDeploy: boolean, + ) {} + + static isContractInstanceDeployedEvent(log: Buffer) { + return toBigIntBE(log.subarray(0, 32)) == DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE; + } + + static fromLogData(log: Buffer) { + if (!this.isContractInstanceDeployedEvent(log)) { + const magicValue = DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE.toString(16); + throw new Error(`Log data for ContractInstanceDeployedEvent is not prefixed with magic value 0x${magicValue}`); + } + const reader = new BufferReader(log.subarray(32)); + const address = reader.readObject(AztecAddress); + const version = reader.readObject(Fr).toNumber(); + const salt = reader.readObject(Fr); + const contractClassId = reader.readObject(Fr); + const initializationHash = reader.readObject(Fr); + const portalContractAddress = EthAddress.fromField(reader.readObject(Fr)); + const publicKeysHash = reader.readObject(Fr); + const universalDeploy = reader.readObject(Fr).toBool(); + + return new ContractInstanceDeployedEvent( + address, + version, + salt, + contractClassId, + initializationHash, + portalContractAddress, + publicKeysHash, + universalDeploy, + ); + } + + toContractInstance(): ContractInstanceWithAddress { + if (this.version !== 1) { + throw new Error(`Unexpected contract instance version ${this.version}`); + } + + return { + address: this.address, + version: this.version, + contractClassId: this.contractClassId, + initializationHash: this.initializationHash, + portalContractAddress: this.portalContractAddress, + publicKeysHash: this.publicKeysHash, + salt: this.salt, + }; + } +} diff --git a/yarn-project/circuits.js/src/contract/index.ts b/yarn-project/circuits.js/src/contract/index.ts index 71ec200a4bb..40ce0f0d8a2 100644 --- a/yarn-project/circuits.js/src/contract/index.ts +++ b/yarn-project/circuits.js/src/contract/index.ts @@ -5,3 +5,6 @@ export * from './contract_class.js'; export * from './artifact_hash.js'; export * from './contract_address.js'; export * from './private_function.js'; +export * from './public_bytecode.js'; +export * from './contract_class_registered_event.js'; +export * from './contract_instance_deployed_event.js'; diff --git a/yarn-project/circuits.js/src/contract/public_bytecode.test.ts b/yarn-project/circuits.js/src/contract/public_bytecode.test.ts new file mode 100644 index 00000000000..e91e8b5cd9f --- /dev/null +++ b/yarn-project/circuits.js/src/contract/public_bytecode.test.ts @@ -0,0 +1,19 @@ +import { ContractArtifact } from '@aztec/foundation/abi'; + +import { getSampleContractArtifact } from '../tests/fixtures.js'; +import { getContractClassFromArtifact } from './contract_class.js'; +import { packBytecode, unpackBytecode } from './public_bytecode.js'; + +describe('PublicBytecode', () => { + let artifact: ContractArtifact; + beforeAll(() => { + artifact = getSampleContractArtifact(); + }); + + it('packs and unpacks public bytecode', () => { + const { publicFunctions } = getContractClassFromArtifact(artifact); + const packedBytecode = packBytecode(publicFunctions); + const unpackedBytecode = unpackBytecode(packedBytecode); + expect(unpackedBytecode).toEqual(publicFunctions); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/public_bytecode.ts b/yarn-project/circuits.js/src/contract/public_bytecode.ts new file mode 100644 index 00000000000..712e5579299 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/public_bytecode.ts @@ -0,0 +1,35 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; +import { + BufferReader, + numToInt32BE, + serializeBufferArrayToVector, + serializeToBuffer, +} from '@aztec/foundation/serialize'; +import { ContractClass } from '@aztec/types/contracts'; + +import { FUNCTION_SELECTOR_NUM_BYTES } from '../constants.gen.js'; + +/** + * Packs together a set of public functions for a contract class. + * @remarks This function should no longer be necessary once we have a single bytecode per contract. + */ +export function packBytecode(publicFns: ContractClass['publicFunctions']): Buffer { + return serializeBufferArrayToVector( + publicFns.map(fn => serializeToBuffer(fn.selector, fn.isInternal, numToInt32BE(fn.bytecode.length), fn.bytecode)), + ); +} + +/** + * Unpacks a set of public functions for a contract class from packed bytecode. + * @remarks This function should no longer be necessary once we have a single bytecode per contract. + */ +export function unpackBytecode(buffer: Buffer): ContractClass['publicFunctions'] { + const reader = BufferReader.asReader(buffer); + return reader.readVector({ + fromBuffer: (reader: BufferReader) => ({ + selector: FunctionSelector.fromBuffer(reader.readBytes(FUNCTION_SELECTOR_NUM_BYTES)), + isInternal: reader.readBoolean(), + bytecode: reader.readBuffer(), + }), + }); +} diff --git a/yarn-project/circuits.js/src/merkle/merkle_tree_calculator.ts b/yarn-project/circuits.js/src/merkle/merkle_tree_calculator.ts index 5f2f4a2c727..388d08a5f2d 100644 --- a/yarn-project/circuits.js/src/merkle/merkle_tree_calculator.ts +++ b/yarn-project/circuits.js/src/merkle/merkle_tree_calculator.ts @@ -23,6 +23,7 @@ export class MerkleTreeCalculator { computeTree(leaves: Buffer[] = []): MerkleTree { if (leaves.length === 0) { + // TODO(#4425): We should be returning a number of nodes that matches the tree height. return new MerkleTree(this.height, [this.zeroHashes[this.zeroHashes.length - 1]]); } diff --git a/yarn-project/circuits.js/src/scripts/constants.in.ts b/yarn-project/circuits.js/src/scripts/constants.in.ts index 14892b1e1fe..6a1dcd6312a 100644 --- a/yarn-project/circuits.js/src/scripts/constants.in.ts +++ b/yarn-project/circuits.js/src/scripts/constants.in.ts @@ -14,7 +14,7 @@ interface ParsedContent { /** * Constants. */ - constants: { [key: string]: number }; + constants: { [key: string]: string }; /** * GeneratorIndexEnum. */ @@ -27,10 +27,10 @@ interface ParsedContent { * @param constants - An object containing key-value pairs representing constants. * @returns A string containing code that exports the constants as TypeScript constants. */ -function processConstantsTS(constants: { [key: string]: number }): string { +function processConstantsTS(constants: { [key: string]: string }): string { const code: string[] = []; Object.entries(constants).forEach(([key, value]) => { - code.push(`export const ${key} = ${value};`); + code.push(`export const ${key} = ${+value > Number.MAX_SAFE_INTEGER ? value + 'n' : value};`); }); return code.join('\n'); } @@ -63,7 +63,7 @@ function processEnumTS(enumName: string, enumValues: { [key: string]: number }): * @param prefix - A prefix to add to the constant names. * @returns A string containing code that exports the constants as Noir constants. */ -function processConstantsSolidity(constants: { [key: string]: number }, prefix = ''): string { +function processConstantsSolidity(constants: { [key: string]: string }, prefix = ''): string { const code: string[] = []; Object.entries(constants).forEach(([key, value]) => { code.push(` uint256 internal constant ${prefix}${key} = ${value};`); @@ -114,7 +114,7 @@ ${processConstantsSolidity(constants)} * Parse the content of the constants file in Noir. */ function parseNoirFile(fileContent: string): ParsedContent { - const constants: { [key: string]: number } = {}; + const constants: { [key: string]: string } = {}; const generatorIndexEnum: { [key: string]: number } = {}; fileContent.split('\n').forEach(l => { @@ -123,7 +123,7 @@ function parseNoirFile(fileContent: string): ParsedContent { return; } - const [, name, _type, value] = line.match(/global\s+(\w+)(\s*:\s*\w+)?\s*=\s*(\d+);/) || []; + const [, name, _type, value] = line.match(/global\s+(\w+)(\s*:\s*\w+)?\s*=\s*(0x[a-fA-F0-9]+|\d+);/) || []; if (!name || !value) { // eslint-disable-next-line no-console console.warn(`Unknown content: ${line}`); @@ -134,7 +134,7 @@ function parseNoirFile(fileContent: string): ParsedContent { if (indexName) { generatorIndexEnum[indexName] = +value; } else { - constants[name] = +value; + constants[name] = value; } }); diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/call_stack_item.test.ts.snap deleted file mode 100644 index 866e12cbb11..00000000000 --- a/yarn-project/circuits.js/src/structs/__snapshots__/call_stack_item.test.ts.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PrivateCallStackItem computes hash 1`] = ` -Fr { - "asBigInt": 18753511695134949302571620808052147141303876532454748772518515365970855750244n, - "asBuffer": { - "data": [ - 41, - 118, - 28, - 137, - 68, - 13, - 118, - 183, - 92, - 239, - 142, - 84, - 234, - 235, - 13, - 55, - 245, - 66, - 184, - 218, - 252, - 190, - 14, - 252, - 58, - 237, - 34, - 161, - 161, - 6, - 106, - 100, - ], - "type": "Buffer", - }, -} -`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap new file mode 100644 index 00000000000..c33c05599b4 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`FunctionData computes empty inputs hash 1`] = ` +Fr { + "asBigInt": 14483571110897883400419490783710119837459619381345566311432831352122387488397n, + "asBuffer": { + "data": [ + 32, + 5, + 105, + 38, + 124, + 15, + 115, + 172, + 137, + 170, + 164, + 20, + 35, + 147, + 152, + 219, + 148, + 69, + 221, + 74, + 211, + 168, + 207, + 55, + 1, + 92, + 213, + 91, + 141, + 76, + 94, + 141, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap index 8a15a59ee84..035cc0c2eb6 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/header.test.ts.snap @@ -2,41 +2,41 @@ exports[`Header computes hash 1`] = ` Fr { - "asBigInt": 17991638921121681345555824161757346486368776085978982802127357651656088857262n, + "asBigInt": 17535834694933389587922737272908689289752880632518238306089028120587248314683n, "asBuffer": { "data": [ - 39, - 198, - 232, - 33, - 120, - 194, - 121, - 42, - 23, - 66, - 111, - 251, - 166, - 131, - 251, - 128, - 16, - 46, - 122, - 209, - 193, - 24, - 177, + 38, + 196, + 238, 67, - 172, - 91, - 198, - 153, - 236, - 93, + 20, + 47, + 99, + 167, + 32, + 178, + 243, + 109, + 29, + 247, 170, - 174, + 104, + 85, + 155, + 139, + 190, + 13, + 63, + 35, + 158, + 188, + 79, + 120, + 214, + 216, + 211, + 169, + 59, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap new file mode 100644 index 00000000000..f62367ae0b2 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_call_stack_item.test.ts.snap @@ -0,0 +1,87 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PrivateCallStackItem computes empty item hash 1`] = ` +Fr { + "asBigInt": 16401401954916832433283065433862370018073001873866502199869260036553314630448n, + "asBuffer": { + "data": [ + 36, + 66, + 221, + 82, + 28, + 89, + 152, + 122, + 66, + 145, + 190, + 15, + 209, + 17, + 152, + 229, + 164, + 216, + 124, + 139, + 195, + 108, + 243, + 182, + 92, + 82, + 41, + 246, + 31, + 195, + 123, + 48, + ], + "type": "Buffer", + }, +} +`; + +exports[`PrivateCallStackItem computes hash 1`] = ` +Fr { + "asBigInt": 8924010543578326968414877575305415789126162162868335105368505150715158785589n, + "asBuffer": { + "data": [ + 19, + 186, + 207, + 155, + 248, + 108, + 56, + 16, + 128, + 141, + 109, + 87, + 227, + 142, + 122, + 152, + 115, + 233, + 32, + 127, + 187, + 119, + 165, + 202, + 131, + 248, + 210, + 183, + 229, + 114, + 238, + 53, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap index f6c7acfcc30..e007f7e33ba 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/private_circuit_public_inputs.test.ts.snap @@ -1,42 +1,85 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = ` +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = ` Fr { - "asBigInt": 7655509707748365385586683354008259293573299722789964529445054772581519738939n, + "asBigInt": 8602604202019666453463173528030293896439191623609170133298184805699713227441n, "asBuffer": { "data": [ - 16, - 236, - 221, - 108, + 19, + 4, + 230, + 196, + 46, + 60, + 83, + 252, + 124, + 145, + 140, + 191, + 30, + 167, + 3, + 51, + 180, 242, - 63, 20, - 45, - 47, - 147, - 239, - 244, - 141, - 4, - 72, + 114, + 108, + 7, + 132, + 207, + 152, + 120, + 205, + 100, + 25, + 103, 218, - 247, - 23, - 13, + 177, + ], + "type": "Buffer", + }, +} +`; + +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = ` +Fr { + "asBigInt": 19351089964096980494056318513856466386221181229656161151672216363848995383227n, + "asBuffer": { + "data": [ + 42, + 200, + 84, + 43, + 44, + 96, + 28, + 45, + 85, + 137, + 80, + 158, + 101, + 170, + 198, + 188, + 188, + 85, + 139, + 179, + 189, + 19, + 207, + 145, + 180, 105, - 121, - 159, - 29, - 162, - 114, - 51, - 52, - 186, - 54, - 94, - 72, - 59, + 57, + 5, + 241, + 123, + 39, + 187, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap new file mode 100644 index 00000000000..24fe6a5e3f8 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_call_stack_item.test.ts.snap @@ -0,0 +1,44 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PublicCallStackItem computes hash 1`] = ` +Fr { + "asBigInt": 19395696808724235586564354338261030411639537309350164360825567543448743585810n, + "asBuffer": { + "data": [ + 42, + 225, + 147, + 74, + 255, + 117, + 70, + 214, + 242, + 250, + 92, + 118, + 98, + 92, + 21, + 18, + 34, + 226, + 246, + 182, + 119, + 107, + 40, + 145, + 163, + 218, + 248, + 163, + 143, + 58, + 40, + 18, + ], + "type": "Buffer", + }, +} +`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap index 574d36a8041..3c27ef02931 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/public_circuit_public_inputs.test.ts.snap @@ -2,41 +2,41 @@ exports[`PublicCircuitPublicInputs hash matches snapshot 1`] = ` Fr { - "asBigInt": 10987106036606499987406426170447920941391129891158672246363150499235953526428n, + "asBigInt": 18998488698478370909936348553101901315705060100426498604017308046889259543837n, "asBuffer": { "data": [ - 24, - 74, - 123, - 76, - 228, - 113, - 134, - 151, - 63, - 27, - 17, - 70, - 189, - 227, - 135, - 146, - 250, - 51, - 192, - 79, - 251, - 233, - 86, - 238, + 42, 0, - 176, - 100, - 200, - 210, - 134, - 70, - 156, + 195, + 119, + 87, + 116, + 9, + 251, + 84, + 111, + 49, + 221, + 110, + 21, + 211, + 9, + 191, + 82, + 247, + 169, + 39, + 25, + 140, + 78, + 50, + 138, + 231, + 209, + 33, + 158, + 173, + 29, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/structs/call_context.ts b/yarn-project/circuits.js/src/structs/call_context.ts index b30a014cadf..b271d282096 100644 --- a/yarn-project/circuits.js/src/structs/call_context.ts +++ b/yarn-project/circuits.js/src/structs/call_context.ts @@ -1,19 +1,14 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; -import { Fr, FunctionSelector } from './index.js'; - /** * Call context. - * @see abis/call_context.hpp */ export class CallContext { - /** - * Address of the portal contract to the storage contract. - */ - public portalContractAddress: EthAddress; constructor( /** * Address of the account which represents the entity who invoked the call. @@ -27,9 +22,8 @@ export class CallContext { public storageContractAddress: AztecAddress, /** * Address of the portal contract to the storage contract. - * Union type is a kludge until C++ has an eth address type. */ - portalContractAddress: EthAddress | Fr, + public portalContractAddress: EthAddress, /** * Function selector of the function being called. */ @@ -50,10 +44,7 @@ export class CallContext { * The start side effect counter for this call context. */ public startSideEffectCounter: number, - ) { - this.portalContractAddress = - portalContractAddress instanceof EthAddress ? portalContractAddress : EthAddress.fromField(portalContractAddress); - } + ) {} /** * Returns a new instance of CallContext with zero msg sender, storage contract address and portal contract address. @@ -63,7 +54,7 @@ export class CallContext { return new CallContext( AztecAddress.ZERO, AztecAddress.ZERO, - Fr.ZERO, + EthAddress.ZERO, FunctionSelector.empty(), false, false, @@ -119,10 +110,10 @@ export class CallContext { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new CallContext( - new AztecAddress(reader.readBytes(32)), - new AztecAddress(reader.readBytes(32)), - new EthAddress(reader.readBytes(32)), - FunctionSelector.fromBuffer(reader.readBytes(4)), + reader.readObject(AztecAddress), + reader.readObject(AztecAddress), + reader.readObject(EthAddress), + reader.readObject(FunctionSelector), reader.readBoolean(), reader.readBoolean(), reader.readBoolean(), @@ -135,7 +126,7 @@ export class CallContext { return new CallContext( reader.readObject(AztecAddress), reader.readObject(AztecAddress), - reader.readField(), + reader.readObject(EthAddress), reader.readObject(FunctionSelector), reader.readBoolean(), reader.readBoolean(), diff --git a/yarn-project/circuits.js/src/structs/call_stack_item.ts b/yarn-project/circuits.js/src/structs/call_stack_item.ts deleted file mode 100644 index 397b1654289..00000000000 --- a/yarn-project/circuits.js/src/structs/call_stack_item.ts +++ /dev/null @@ -1,189 +0,0 @@ -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import { computePrivateCallStackItemHash, computePublicCallStackItemHash } from '../abis/abis.js'; -import { CallRequest, CallerContext } from './call_request.js'; -import { FunctionData } from './function_data.js'; -import { PrivateCircuitPublicInputs } from './private_circuit_public_inputs.js'; -import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; - -/** - * Call stack item on a private call. - */ -export class PrivateCallStackItem { - constructor( - /** - * Address of the contract on which the function is invoked. - */ - public contractAddress: AztecAddress, - /** - * Data identifying the function being called. - */ - public functionData: FunctionData, - /** - * Public inputs to the private kernel circuit. - */ - public publicInputs: PrivateCircuitPublicInputs, - /** - * Whether the current callstack item should be considered a public fn execution request. - */ - public readonly isExecutionRequest: boolean, - ) { - if (isExecutionRequest) { - throw new Error('boolean isExecutionRequest must be set to true for a PrivateCallStackItem object'); - } - } - - toBuffer() { - return serializeToBuffer(this.contractAddress, this.functionData, this.publicInputs, this.isExecutionRequest); - } - - toFields(): Fr[] { - return [ - this.contractAddress.toField(), - ...this.functionData.toFields(), - ...this.publicInputs.toFields(), - new Fr(this.isExecutionRequest), - ]; - } - - /** - * Deserializes from a buffer or reader. - * @param buffer - Buffer or reader to read from. - * @returns The deserialized instance. - */ - static fromBuffer(buffer: Buffer | BufferReader): PrivateCallStackItem { - const reader = BufferReader.asReader(buffer); - return new PrivateCallStackItem( - reader.readObject(AztecAddress), - reader.readObject(FunctionData), - reader.readObject(PrivateCircuitPublicInputs), - reader.readBoolean(), - ); - } - - static fromFields(fields: Fr[] | FieldReader): PrivateCallStackItem { - const reader = FieldReader.asReader(fields); - - const contractAddress = AztecAddress.fromFields(reader); - const functionData = FunctionData.fromFields(reader); - const publicInputs = PrivateCircuitPublicInputs.fromFields(reader); - const isExecutionRequest = reader.readBoolean(); - - return new PrivateCallStackItem(contractAddress, functionData, publicInputs, isExecutionRequest); - } - - /** - * Returns a new instance of PrivateCallStackItem with zero contract address, function data and public inputs. - * @returns A new instance of PrivateCallStackItem with zero contract address, function data and public inputs. - */ - public static empty(): PrivateCallStackItem { - return new PrivateCallStackItem( - AztecAddress.ZERO, - FunctionData.empty({ isPrivate: true }), - PrivateCircuitPublicInputs.empty(), - false, - ); - } - - isEmpty() { - return this.contractAddress.isZero() && this.functionData.isEmpty() && this.publicInputs.isEmpty(); - } - - /** - * Computes this call stack item hash. - * @returns Hash. - */ - public hash() { - return computePrivateCallStackItemHash(this); - } - - /** - * Creates a new CallRequest with values of the calling contract. - * @returns A CallRequest instance with the contract address, caller context, and the hash of the call stack item. - */ - public toCallRequest() { - if (this.isEmpty()) { - return CallRequest.empty(); - } - - const callContext = this.publicInputs.callContext; - const callerContext = callContext.isDelegateCall - ? new CallerContext(callContext.msgSender, callContext.storageContractAddress) - : CallerContext.empty(); - // todo: populate side effect counters correctly - return new CallRequest(this.hash(), callContext.msgSender, callerContext, Fr.ZERO, Fr.ZERO); - } -} - -/** - * Call stack item on a public call. - * @see cpp/src/aztec3/circuits/abis/call_stack_item.hpp. - */ -export class PublicCallStackItem { - constructor( - /** - * Address of the contract on which the function is invoked. - */ - public contractAddress: AztecAddress, - /** - * Data identifying the function being called. - */ - public functionData: FunctionData, - /** - * Public inputs to the public kernel circuit. - */ - public publicInputs: PublicCircuitPublicInputs, - /** - * Whether the current callstack item should be considered a public fn execution request. - */ - public isExecutionRequest: boolean, - ) {} - - toBuffer() { - return serializeToBuffer(this.contractAddress, this.functionData, this.publicInputs, this.isExecutionRequest); - } - - /** - * Returns a new instance of PublicCallStackItem with zero contract address, function data and public inputs. - * @returns A new instance of PublicCallStackItem with zero contract address, function data and public inputs. - */ - public static empty(): PublicCallStackItem { - return new PublicCallStackItem( - AztecAddress.ZERO, - FunctionData.empty({ isPrivate: false }), - PublicCircuitPublicInputs.empty(), - false, - ); - } - - isEmpty() { - return this.contractAddress.isZero() && this.functionData.isEmpty() && this.publicInputs.isEmpty(); - } - - /** - * Computes this call stack item hash. - * @returns Hash. - */ - public hash() { - return computePublicCallStackItemHash(this); - } - - /** - * Creates a new CallRequest with values of the calling contract. - * @returns A CallRequest instance with the contract address, caller context, and the hash of the call stack item. - */ - public toCallRequest() { - if (this.isEmpty()) { - return CallRequest.empty(); - } - - const callContext = this.publicInputs.callContext; - const callerContext = callContext.isDelegateCall - ? new CallerContext(callContext.msgSender, callContext.storageContractAddress) - : CallerContext.empty(); - // todo: populate side effect counters correctly - return new CallRequest(this.hash(), callContext.msgSender, callerContext, Fr.ZERO, Fr.ZERO); - } -} diff --git a/yarn-project/circuits.js/src/structs/complete_address.ts b/yarn-project/circuits.js/src/structs/complete_address.ts index 226a3d5a76f..da3d0be17b1 100644 --- a/yarn-project/circuits.js/src/structs/complete_address.ts +++ b/yarn-project/circuits.js/src/structs/complete_address.ts @@ -3,13 +3,10 @@ import { Fr, GrumpkinScalar, Point } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import { Grumpkin } from '../barretenberg/index.js'; -import { - GrumpkinPrivateKey, - PartialAddress, - PublicKey, - computeContractAddressFromPartial, - computePartialAddress, -} from '../index.js'; +import { computeContractAddressFromPartial, computePartialAddress } from '../contract/contract_address.js'; +import { GrumpkinPrivateKey } from '../types/grumpkin_private_key.js'; +import { PartialAddress } from '../types/partial_address.js'; +import { PublicKey } from '../types/public_key.js'; /** * A complete address is a combination of an Aztec address, a public key and a partial address. diff --git a/yarn-project/circuits.js/src/structs/contract_deployment_data.ts b/yarn-project/circuits.js/src/structs/contract_deployment_data.ts index d99d15044a0..4f154ace1ae 100644 --- a/yarn-project/circuits.js/src/structs/contract_deployment_data.ts +++ b/yarn-project/circuits.js/src/structs/contract_deployment_data.ts @@ -1,6 +1,8 @@ +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { EthAddress, Fr, Point, PublicKey } from '../index.js'; +import { PublicKey } from '../types/public_key.js'; /** * Contract deployment data in a TxContext @@ -70,18 +72,18 @@ export class ContractDeploymentData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), - new EthAddress(reader.readBytes(32)), + reader.readObject(EthAddress), ); } static fromFields(fields: Fr[] | FieldReader): ContractDeploymentData { const reader = FieldReader.asReader(fields); - const publicKey = Point.fromFields(reader); + const publicKey = reader.readObject(Point); const initializationHash = reader.readField(); const contractClassId = reader.readField(); const contractAddressSalt = reader.readField(); - const portalContractAddress = new EthAddress(reader.readField().toBuffer()); + const portalContractAddress = reader.readObject(EthAddress); return new ContractDeploymentData( publicKey, diff --git a/yarn-project/circuits.js/src/structs/function_data.test.ts b/yarn-project/circuits.js/src/structs/function_data.test.ts index 4a953ccdb0c..85ddf5a6730 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -21,4 +21,13 @@ describe('FunctionData', () => { const fields = functionData.toFields(); expect(fields.length).toBe(FUNCTION_DATA_LENGTH); }); + + it('computes empty inputs hash', () => { + const data = FunctionData.empty(); + const hash = data.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in private_circuit_public_inputs.nr + // console.log("hash", hash.toString()); + }); }); diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index d35eb8dfffa..378baab9f94 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -1,7 +1,10 @@ import { FunctionAbi, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { pedersenHash } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { ContractFunctionDao, Fr } from '../index.js'; +import { GeneratorIndex } from '../constants.gen.js'; +import { ContractFunctionDao } from '../types/contract_function_dao.js'; /** * Function description for circuit. @@ -108,4 +111,13 @@ export class FunctionData { return new FunctionData(selector, isInternal, isPrivate, isConstructor); } + + hash(): Fr { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(field => field.toBuffer()), + GeneratorIndex.FUNCTION_DATA, + ), + ); + } } diff --git a/yarn-project/circuits.js/src/structs/global_variables.ts b/yarn-project/circuits.js/src/structs/global_variables.ts index fd33663ba6c..49ecf601b46 100644 --- a/yarn-project/circuits.js/src/structs/global_variables.ts +++ b/yarn-project/circuits.js/src/structs/global_variables.ts @@ -2,27 +2,25 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; +import { AztecAddress, EthAddress } from './index.js'; + /** * Global variables of the L2 block. */ export class GlobalVariables { constructor( - /** - * ChainId for the L2 block. - */ + /** ChainId for the L2 block. */ public chainId: Fr, - /** - * version for the L2 block. - */ + /** Version for the L2 block. */ public version: Fr, - /** - * Block number of the L2 block. - */ + /** Block number of the L2 block. */ public blockNumber: Fr, - /** - * Timestamp of the L2 block. - */ + /** Timestamp of the L2 block. */ public timestamp: Fr, + /** Recipient of block reward. */ + public coinbase: EthAddress, + /** Address to receive fees. */ + public feeRecipient: AztecAddress, ) {} static from(fields: FieldsOf): GlobalVariables { @@ -30,7 +28,7 @@ export class GlobalVariables { } static empty(): GlobalVariables { - return new GlobalVariables(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO); + return new GlobalVariables(Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, EthAddress.ZERO, AztecAddress.ZERO); } static fromBuffer(buffer: Buffer | BufferReader): GlobalVariables { @@ -40,6 +38,8 @@ export class GlobalVariables { Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), + reader.readObject(EthAddress), + reader.readObject(AztecAddress), ); } @@ -49,18 +49,34 @@ export class GlobalVariables { Fr.fromString(obj.version), Fr.fromString(obj.blockNumber), Fr.fromString(obj.timestamp), + EthAddress.fromString(obj.coinbase), + AztecAddress.fromString(obj.feeRecipient), ); } static fromFields(fields: Fr[] | FieldReader): GlobalVariables { const reader = FieldReader.asReader(fields); - return new GlobalVariables(reader.readField(), reader.readField(), reader.readField(), reader.readField()); + return new GlobalVariables( + reader.readField(), + reader.readField(), + reader.readField(), + reader.readField(), + EthAddress.fromField(reader.readField()), + AztecAddress.fromField(reader.readField()), + ); } static getFields(fields: FieldsOf) { // Note: The order here must match the order in the HeaderLib solidity library. - return [fields.chainId, fields.version, fields.blockNumber, fields.timestamp] as const; + return [ + fields.chainId, + fields.version, + fields.blockNumber, + fields.timestamp, + fields.coinbase, + fields.feeRecipient, + ] as const; } toBuffer() { @@ -77,10 +93,19 @@ export class GlobalVariables { version: this.version.toString(), blockNumber: this.blockNumber.toString(), timestamp: this.timestamp.toString(), + coinbase: this.coinbase.toString(), + feeRecipient: this.feeRecipient.toString(), }; } isEmpty(): boolean { - return this.chainId.isZero() && this.version.isZero() && this.blockNumber.isZero() && this.timestamp.isZero(); + return ( + this.chainId.isZero() && + this.version.isZero() && + this.blockNumber.isZero() && + this.timestamp.isZero() && + this.coinbase.isZero() && + this.feeRecipient.isZero() + ); } } diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index cb06d1b1412..20609e8fe5d 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -2,7 +2,6 @@ export * from '@aztec/foundation/eth-address'; export * from './aggregation_object.js'; export * from './call_context.js'; export * from './call_request.js'; -export * from './call_stack_item.js'; export * from './complete_address.js'; export * from './contract_deployment_data.js'; export * from './contract_storage_read.js'; @@ -20,9 +19,11 @@ export * from './kernel/public_inputs_final.js'; export * from './kernel/public_kernel.js'; export * from './membership_witness.js'; export * from './nullifier_key_validation_request.js'; +export * from './private_call_stack_item.js'; export * from './private_circuit_public_inputs.js'; export * from './proof.js'; export * from './public_call_request.js'; +export * from './public_call_stack_item.js'; export * from './public_circuit_public_inputs.js'; export * from './read_request_membership_witness.js'; export * from './rollup/append_only_tree_snapshot.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index fb86aefbad9..fdc25b44dea 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -1,32 +1,29 @@ import { makeTuple } from '@aztec/foundation/array'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; import { MAX_NEW_COMMITMENTS_PER_TX, + MAX_NEW_COMMITMENTS_PER_TX_META, MAX_NEW_CONTRACTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX_META, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_READ_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; -import { - AggregationObject, - AztecAddress, - EthAddress, - Fr, - FunctionData, - NullifierKeyValidationRequestContext, - SideEffect, - SideEffectLinkedToNoteHash, -} from '../index.js'; +import { NullifierKeyValidationRequestContext } from '../nullifier_key_validation_request.js'; +import { SideEffect, SideEffectLinkedToNoteHash } from '../side_effects.js'; /** * The information assembled after the contract deployment was processed by the private kernel circuit. @@ -34,10 +31,6 @@ import { * Note: Not to be confused with `ContractDeploymentData`. */ export class NewContractData { - /** - * Ethereum address of the portal contract on L1. - */ - public portalContractAddress: EthAddress; constructor( /** * Aztec address of the contract. @@ -45,18 +38,13 @@ export class NewContractData { public contractAddress: AztecAddress, /** * Ethereum address of the portal contract on L1. - * TODO(AD): refactor this later - * currently there is a kludge with circuits cpp as it emits an AztecAddress */ - portalContractAddress: EthAddress | AztecAddress, + public portalContractAddress: EthAddress, /** * Contract class id. */ public contractClassId: Fr, - ) { - // Handle circuits emitting this as an AztecAddress - this.portalContractAddress = new EthAddress(portalContractAddress.toBuffer()); - } + ) {} toBuffer() { return serializeToBuffer(this.contractAddress, this.portalContractAddress, this.contractClassId); @@ -69,11 +57,7 @@ export class NewContractData { */ static fromBuffer(buffer: Buffer | BufferReader): NewContractData { const reader = BufferReader.asReader(buffer); - return new NewContractData( - reader.readObject(AztecAddress), - new EthAddress(reader.readBytes(32)), - Fr.fromBuffer(reader), - ); + return new NewContractData(reader.readObject(AztecAddress), reader.readObject(EthAddress), Fr.fromBuffer(reader)); } static empty() { @@ -81,105 +65,6 @@ export class NewContractData { } } -/** - * Info which a user might want to reveal to the world. - * Note: Currently not used (2023-05-12). - */ -export class OptionallyRevealedData { - /** - * Address of the portal contract corresponding to the L2 contract on which the function above was invoked. - * - * TODO(AD): refactor this later - * currently there is a kludge with circuits cpp as it emits an AztecAddress - */ - public portalContractAddress: EthAddress; - constructor( - /** - * Hash of the call stack item from which this info was originates. - */ - public callStackItemHash: Fr, - /** - * Function data of a function call from which this info originates. - */ - public functionData: FunctionData, - /** - * Verification key hash of the function call from which this info originates. - */ - public vkHash: Fr, - /** - * Address of the portal contract corresponding to the L2 contract on which the function above was invoked. - * - * TODO(AD): refactor this later - * currently there is a kludge with circuits cpp as it emits an AztecAddress - */ - portalContractAddress: EthAddress | AztecAddress, - /** - * Whether the fee was paid from the L1 account of the user. - */ - public payFeeFromL1: boolean, - /** - * Whether the fee was paid from a public account on L2. - */ - public payFeeFromPublicL2: boolean, - /** - * Whether the function call was invoked from L1. - */ - public calledFromL1: boolean, - /** - * Whether the function call was invoked from the public L2 account of the user. - */ - public calledFromPublicL2: boolean, - ) { - // Handle circuits emitting this as an AztecAddress - this.portalContractAddress = EthAddress.fromField(portalContractAddress.toField()); - } - - toBuffer() { - return serializeToBuffer( - this.callStackItemHash, - this.functionData, - this.vkHash, - this.portalContractAddress, - this.payFeeFromL1, - this.payFeeFromPublicL2, - this.calledFromL1, - this.calledFromPublicL2, - ); - } - - /** - * Deserializes from a buffer or reader, corresponding to a write in cpp. - * @param buffer - Buffer or reader to read from. - * @returns The deserialized OptionallyRevealedData. - */ - static fromBuffer(buffer: Buffer | BufferReader): OptionallyRevealedData { - const reader = BufferReader.asReader(buffer); - return new OptionallyRevealedData( - Fr.fromBuffer(reader), - reader.readObject(FunctionData), - Fr.fromBuffer(reader), - new EthAddress(reader.readBytes(32)), - reader.readBoolean(), - reader.readBoolean(), - reader.readBoolean(), - reader.readBoolean(), - ); - } - - static empty() { - return new OptionallyRevealedData( - Fr.ZERO, - FunctionData.empty(), - Fr.ZERO, - EthAddress.ZERO, - false, - false, - false, - false, - ); - } -} - /** * Read operations from the public state tree. */ @@ -293,10 +178,6 @@ export class PublicDataUpdateRequest { */ export class CombinedAccumulatedData { constructor( - /** - * Aggregated proof of all the previous kernel iterations. - */ - public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations /** * All the read requests made in this transaction. */ @@ -350,10 +231,6 @@ export class CombinedAccumulatedData { * All the new contracts deployed in this transaction. */ public newContracts: Tuple, - /** - * All the optionally revealed data in this transaction. - */ - public optionallyRevealedData: Tuple, /** * All the public data update requests made in this transaction. */ @@ -366,7 +243,6 @@ export class CombinedAccumulatedData { toBuffer() { return serializeToBuffer( - this.aggregationObject, this.readRequests, this.nullifierKeyValidationRequests, this.newCommitments, @@ -379,14 +255,13 @@ export class CombinedAccumulatedData { this.encryptedLogPreimagesLength, this.unencryptedLogPreimagesLength, this.newContracts, - this.optionallyRevealedData, this.publicDataUpdateRequests, this.publicDataReads, ); } toString() { - return this.toBuffer().toString(); + return this.toBuffer().toString('hex'); } /** @@ -397,7 +272,6 @@ export class CombinedAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): CombinedAccumulatedData { const reader = BufferReader.asReader(buffer); return new CombinedAccumulatedData( - reader.readObject(AggregationObject), reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_NEW_COMMITMENTS_PER_TX, SideEffect), @@ -410,7 +284,6 @@ export class CombinedAccumulatedData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_NEW_CONTRACTS_PER_TX, NewContractData), - reader.readArray(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); @@ -418,7 +291,6 @@ export class CombinedAccumulatedData { static fromFinalAccumulatedData(finalData: FinalAccumulatedData): CombinedAccumulatedData { return new CombinedAccumulatedData( - finalData.aggregationObject, makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), finalData.newCommitments, @@ -431,7 +303,6 @@ export class CombinedAccumulatedData { finalData.encryptedLogPreimagesLength, finalData.unencryptedLogPreimagesLength, finalData.newContracts, - finalData.optionallyRevealedData, makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); @@ -448,7 +319,6 @@ export class CombinedAccumulatedData { static empty() { return new CombinedAccumulatedData( - AggregationObject.makeFake(), makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_NEW_COMMITMENTS_PER_TX, SideEffect.empty), @@ -461,7 +331,6 @@ export class CombinedAccumulatedData { Fr.zero(), Fr.zero(), makeTuple(MAX_NEW_CONTRACTS_PER_TX, NewContractData.empty), - makeTuple(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData.empty), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); @@ -474,10 +343,6 @@ export class CombinedAccumulatedData { */ export class FinalAccumulatedData { constructor( - /** - * Aggregated proof of all the previous kernel iterations. - */ - public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations /** * The new commitments made in this transaction. */ @@ -521,15 +386,10 @@ export class FinalAccumulatedData { * All the new contracts deployed in this transaction. */ public newContracts: Tuple, - /** - * All the optionally revealed data in this transaction. - */ - public optionallyRevealedData: Tuple, ) {} toBuffer() { return serializeToBuffer( - this.aggregationObject, this.newCommitments, this.newNullifiers, this.privateCallStack, @@ -540,12 +400,11 @@ export class FinalAccumulatedData { this.encryptedLogPreimagesLength, this.unencryptedLogPreimagesLength, this.newContracts, - this.optionallyRevealedData, ); } toString() { - return this.toBuffer().toString(); + return this.toBuffer().toString('hex'); } /** @@ -556,7 +415,6 @@ export class FinalAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): FinalAccumulatedData { const reader = BufferReader.asReader(buffer); return new FinalAccumulatedData( - reader.readObject(AggregationObject), reader.readArray(MAX_NEW_COMMITMENTS_PER_TX, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -567,7 +425,6 @@ export class FinalAccumulatedData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_NEW_CONTRACTS_PER_TX, NewContractData), - reader.readArray(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData), ); } @@ -582,7 +439,6 @@ export class FinalAccumulatedData { static empty() { return new FinalAccumulatedData( - AggregationObject.makeFake(), makeTuple(MAX_NEW_COMMITMENTS_PER_TX, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -593,7 +449,52 @@ export class FinalAccumulatedData { Fr.zero(), Fr.zero(), makeTuple(MAX_NEW_CONTRACTS_PER_TX, NewContractData.empty), - makeTuple(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, OptionallyRevealedData.empty), + ); + } +} + +export class AccumulatedMetaData { + constructor( + /** + * The new commitments made in this transaction. + */ + public newCommitments: Tuple, + /** + * The new nullifiers made in this transaction. + */ + public newNullifiers: Tuple, + /** + * Current public call stack. + */ + public publicCallStack: Tuple, + ) {} + + toBuffer() { + return serializeToBuffer(this.newCommitments, this.newNullifiers, this.publicCallStack); + } + + static fromBuffer(buffer: Buffer | BufferReader): AccumulatedMetaData { + const reader = BufferReader.asReader(buffer); + return new AccumulatedMetaData( + reader.readArray(MAX_NEW_COMMITMENTS_PER_TX_META, SideEffect), + reader.readArray(MAX_NEW_NULLIFIERS_PER_TX_META, SideEffectLinkedToNoteHash), + reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, CallRequest), + ); + } + + toString() { + return this.toBuffer().toString('hex'); + } + + static fromString(str: string) { + return AccumulatedMetaData.fromBuffer(Buffer.from(str, 'hex')); + } + + static empty() { + return new AccumulatedMetaData( + makeTuple(MAX_NEW_COMMITMENTS_PER_TX_META, SideEffect.empty), + makeTuple(MAX_NEW_NULLIFIERS_PER_TX_META, SideEffectLinkedToNoteHash.empty), + makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, CallRequest.empty), ); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/previous_kernel_data.ts b/yarn-project/circuits.js/src/structs/kernel/previous_kernel_data.ts index 331d6c5c8fe..27303406f77 100644 --- a/yarn-project/circuits.js/src/structs/kernel/previous_kernel_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/previous_kernel_data.ts @@ -2,7 +2,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; -import { VK_TREE_HEIGHT } from '../../index.js'; +import { VK_TREE_HEIGHT } from '../../constants.gen.js'; import { Proof, makeEmptyProof } from '../proof.js'; import { UInt32 } from '../shared.js'; import { VerificationKey } from '../verification_key.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel.test.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel.test.ts index b6abcbbcb42..f69c2a63760 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel.test.ts @@ -1,11 +1,10 @@ +// TODO(#4411): this is mostly redundant. Nuke this import { makeCallRequest, makeFinalAccumulatedData, makeNewSideEffect, makePreviousKernelData, makePrivateCallData, - makePrivateCallStackItem, - makePrivateCircuitPublicInputs, makePrivateKernelInputsInner, makePrivateKernelPublicInputsFinal, } from '../../tests/factories.js'; @@ -13,8 +12,6 @@ import { CallRequest, FinalAccumulatedData, PreviousKernelData, - PrivateCallStackItem, - PrivateCircuitPublicInputs, PrivateKernelPublicInputsFinal, SideEffect, } from '../index.js'; @@ -76,20 +73,3 @@ describe('CallRequest', () => { expect(CallRequest.fromBuffer(buf)).toEqual(fad); }); }); - -describe('PrivateCallStackcItem', () => { - it('convert to and from buffer', () => { - const fad = makePrivateCallStackItem(0); - - const buf = fad.toBuffer(); - expect(PrivateCallStackItem.fromBuffer(buf)).toEqual(fad); - }); -}); - -describe('Private Circuit Public Inputs', () => { - it('convert to and from buffer', () => { - const pkpi = makePrivateCircuitPublicInputs(); - const buf = pkpi.toBuffer(); - expect(PrivateCircuitPublicInputs.fromBuffer(buf)).toEqual(pkpi); - }); -}); diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts index c75cc18abf8..e5e67f05179 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel.ts @@ -14,8 +14,8 @@ import { } from '../../constants.gen.js'; import { GrumpkinPrivateKey } from '../../types/grumpkin_private_key.js'; import { CallRequest } from '../call_request.js'; -import { PrivateCallStackItem } from '../call_stack_item.js'; import { MembershipWitness } from '../membership_witness.js'; +import { PrivateCallStackItem } from '../private_call_stack_item.js'; import { Proof } from '../proof.js'; import { ReadRequestMembershipWitness } from '../read_request_membership_witness.js'; import { SideEffect, SideEffectLinkedToNoteHash } from '../side_effects.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_inputs.ts index eb90a8ffe80..03572bf76dd 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_inputs.ts @@ -1,5 +1,7 @@ +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { AggregationObject } from '../aggregation_object.js'; import { CombinedAccumulatedData } from './combined_accumulated_data.js'; import { CombinedConstantData } from './combined_constant_data.js'; @@ -8,6 +10,14 @@ import { CombinedConstantData } from './combined_constant_data.js'; */ export class KernelCircuitPublicInputs { constructor( + /** + * Aggregated proof of all the previous kernel iterations. + */ + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * The side effect counter that meta side effects are all beneath. + */ + public metaHwm: Fr, /** * Data accumulated from both public and private circuits. */ @@ -23,7 +33,7 @@ export class KernelCircuitPublicInputs { ) {} toBuffer() { - return serializeToBuffer(this.end, this.constants, this.isPrivate); + return serializeToBuffer(this.aggregationObject, this.metaHwm, this.end, this.constants, this.isPrivate); } /** @@ -34,6 +44,8 @@ export class KernelCircuitPublicInputs { static fromBuffer(buffer: Buffer | BufferReader): KernelCircuitPublicInputs { const reader = BufferReader.asReader(buffer); return new KernelCircuitPublicInputs( + reader.readObject(AggregationObject), + reader.readObject(Fr), reader.readObject(CombinedAccumulatedData), reader.readObject(CombinedConstantData), reader.readBoolean(), @@ -41,7 +53,13 @@ export class KernelCircuitPublicInputs { } static empty() { - return new KernelCircuitPublicInputs(CombinedAccumulatedData.empty(), CombinedConstantData.empty(), true); + return new KernelCircuitPublicInputs( + AggregationObject.makeFake(), + Fr.zero(), + CombinedAccumulatedData.empty(), + CombinedConstantData.empty(), + true, + ); } } @@ -49,12 +67,22 @@ export class KernelCircuitPublicInputs { * Public inputs of the public kernel circuit. */ export class PublicKernelPublicInputs extends KernelCircuitPublicInputs { - constructor(end: CombinedAccumulatedData, constants: CombinedConstantData) { - super(end, constants, false); + constructor( + aggregationObject: AggregationObject, + metaHwm: Fr, + end: CombinedAccumulatedData, + constants: CombinedConstantData, + ) { + super(aggregationObject, metaHwm, end, constants, false); } static empty(): PublicKernelPublicInputs { - return new PublicKernelPublicInputs(CombinedAccumulatedData.empty(), CombinedConstantData.empty()); + return new PublicKernelPublicInputs( + AggregationObject.makeFake(), + Fr.zero(), + CombinedAccumulatedData.empty(), + CombinedConstantData.empty(), + ); } } @@ -62,11 +90,21 @@ export class PublicKernelPublicInputs extends KernelCircuitPublicInputs { * Public inputs of the private kernel circuit. */ export class PrivateKernelPublicInputs extends KernelCircuitPublicInputs { - constructor(end: CombinedAccumulatedData, constants: CombinedConstantData) { - super(end, constants, true); + constructor( + aggregationObject: AggregationObject, + metaHwm: Fr, + end: CombinedAccumulatedData, + constants: CombinedConstantData, + ) { + super(aggregationObject, metaHwm, end, constants, true); } static empty(): PrivateKernelPublicInputs { - return new PrivateKernelPublicInputs(CombinedAccumulatedData.empty(), CombinedConstantData.empty()); + return new PrivateKernelPublicInputs( + AggregationObject.makeFake(), + Fr.zero(), + CombinedAccumulatedData.empty(), + CombinedConstantData.empty(), + ); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts b/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts index af47ac9a846..08142cb95f7 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_inputs_final.ts @@ -1,6 +1,8 @@ +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { FinalAccumulatedData } from './combined_accumulated_data.js'; +import { AggregationObject } from '../aggregation_object.js'; +import { AccumulatedMetaData, FinalAccumulatedData } from './combined_accumulated_data.js'; import { CombinedConstantData } from './combined_constant_data.js'; /** @@ -8,6 +10,18 @@ import { CombinedConstantData } from './combined_constant_data.js'; */ export class KernelCircuitPublicInputsFinal { constructor( + /** + * Aggregated proof of all the previous kernel iterations. + */ + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * The side effect counter that meta side effects are all beneath. + */ + public metaHwm: Fr, + /** + * Final metadata accumulated for ordering private kernel circuit. + */ + public endMeta: AccumulatedMetaData, /** * Final data accumulated for ordering private kernel circuit. */ @@ -23,7 +37,14 @@ export class KernelCircuitPublicInputsFinal { ) {} toBuffer() { - return serializeToBuffer(this.end, this.constants, this.isPrivate); + return serializeToBuffer( + this.aggregationObject, + this.metaHwm, + this.endMeta, + this.end, + this.constants, + this.isPrivate, + ); } /** @@ -34,6 +55,9 @@ export class KernelCircuitPublicInputsFinal { static fromBuffer(buffer: Buffer | BufferReader): KernelCircuitPublicInputsFinal { const reader = BufferReader.asReader(buffer); return new KernelCircuitPublicInputsFinal( + reader.readObject(AggregationObject), + reader.readObject(Fr), + reader.readObject(AccumulatedMetaData), reader.readObject(FinalAccumulatedData), reader.readObject(CombinedConstantData), reader.readBoolean(), @@ -41,7 +65,14 @@ export class KernelCircuitPublicInputsFinal { } static empty() { - return new KernelCircuitPublicInputsFinal(FinalAccumulatedData.empty(), CombinedConstantData.empty(), true); + return new KernelCircuitPublicInputsFinal( + AggregationObject.makeFake(), + Fr.zero(), + AccumulatedMetaData.empty(), + FinalAccumulatedData.empty(), + CombinedConstantData.empty(), + true, + ); } } @@ -49,7 +80,13 @@ export class KernelCircuitPublicInputsFinal { * Public inputs of the final private kernel circuit. */ export class PrivateKernelPublicInputsFinal extends KernelCircuitPublicInputsFinal { - constructor(end: FinalAccumulatedData, constants: CombinedConstantData) { - super(end, constants, true); + constructor( + aggregationObject: AggregationObject, + metaHwm: Fr, + endMeta: AccumulatedMetaData, + end: FinalAccumulatedData, + constants: CombinedConstantData, + ) { + super(aggregationObject, metaHwm, endMeta, end, constants, true); } } diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel.ts index c9223b2c3a9..e6eaa46200f 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel.ts @@ -9,9 +9,9 @@ import { PUBLIC_DATA_TREE_HEIGHT, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; -import { PublicCallStackItem } from '../call_stack_item.js'; import { MembershipWitness } from '../membership_witness.js'; import { Proof } from '../proof.js'; +import { PublicCallStackItem } from '../public_call_stack_item.js'; import { PreviousKernelData } from './previous_kernel_data.js'; /** diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts new file mode 100644 index 00000000000..a47f725551e --- /dev/null +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.test.ts @@ -0,0 +1,45 @@ +import { PRIVATE_CALL_STACK_ITEM_LENGTH } from '../constants.gen.js'; +import { makePrivateCallStackItem } from '../tests/factories.js'; +import { PrivateCallStackItem } from './private_call_stack_item.js'; + +describe('PrivateCallStackItem', () => { + let item: PrivateCallStackItem; + + beforeAll(() => { + const randomInt = Math.floor(Math.random() * 1000); + item = makePrivateCallStackItem(randomInt); + }); + + it('serializes to buffer and deserializes it back', () => { + const buffer = item.toBuffer(); + const res = PrivateCallStackItem.fromBuffer(buffer); + expect(res).toEqual(item); + }); + + it('serializes to field array and deserializes it back', () => { + const fieldArray = item.toFields(); + const res = PrivateCallStackItem.fromFields(fieldArray); + expect(res).toEqual(item); + }); + + it('number of fields matches constant', () => { + const fields = item.toFields(); + expect(fields.length).toBe(PRIVATE_CALL_STACK_ITEM_LENGTH); + }); + + it('computes hash', () => { + const seed = 9870243; + const item = makePrivateCallStackItem(seed); + const hash = item.hash(); + expect(hash).toMatchSnapshot(); + }); + + it('computes empty item hash', () => { + const item = PrivateCallStackItem.empty(); + const hash = item.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in private_call_stack_item.nr + // console.log("hash", hash.toString()); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/private_call_stack_item.ts b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts new file mode 100644 index 00000000000..fb4ceee298b --- /dev/null +++ b/yarn-project/circuits.js/src/structs/private_call_stack_item.ts @@ -0,0 +1,111 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { pedersenHash } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { GeneratorIndex } from '../constants.gen.js'; +import { CallRequest, CallerContext } from './call_request.js'; +import { FunctionData } from './function_data.js'; +import { PrivateCircuitPublicInputs } from './private_circuit_public_inputs.js'; + +/** + * Call stack item on a private call. + */ +export class PrivateCallStackItem { + constructor( + /** + * Address of the contract on which the function is invoked. + */ + public contractAddress: AztecAddress, + /** + * Data identifying the function being called. + */ + public functionData: FunctionData, + /** + * Public inputs to the private kernel circuit. + */ + public publicInputs: PrivateCircuitPublicInputs, + ) {} + + static getFields(fields: FieldsOf) { + return [fields.contractAddress, fields.functionData, fields.publicInputs] as const; + } + + toBuffer() { + return serializeToBuffer(...PrivateCallStackItem.getFields(this)); + } + + toFields(): Fr[] { + return serializeToFields(...PrivateCallStackItem.getFields(this)); + } + + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer(buffer: Buffer | BufferReader): PrivateCallStackItem { + const reader = BufferReader.asReader(buffer); + return new PrivateCallStackItem( + reader.readObject(AztecAddress), + reader.readObject(FunctionData), + reader.readObject(PrivateCircuitPublicInputs), + ); + } + + static fromFields(fields: Fr[] | FieldReader): PrivateCallStackItem { + const reader = FieldReader.asReader(fields); + return new PrivateCallStackItem( + AztecAddress.fromFields(reader), + FunctionData.fromFields(reader), + PrivateCircuitPublicInputs.fromFields(reader), + ); + } + + /** + * Returns a new instance of PrivateCallStackItem with zero contract address, function data and public inputs. + * @returns A new instance of PrivateCallStackItem with zero contract address, function data and public inputs. + */ + public static empty(): PrivateCallStackItem { + return new PrivateCallStackItem( + AztecAddress.ZERO, + FunctionData.empty({ isPrivate: true }), + PrivateCircuitPublicInputs.empty(), + ); + } + + isEmpty() { + return this.contractAddress.isZero() && this.functionData.isEmpty() && this.publicInputs.isEmpty(); + } + + /** + * Computes this call stack item hash. + * @returns Hash. + */ + public hash(): Fr { + return Fr.fromBuffer( + pedersenHash( + this.toFields().map(field => field.toBuffer()), + GeneratorIndex.CALL_STACK_ITEM, + ), + ); + } + + /** + * Creates a new CallRequest with values of the calling contract. + * @returns A CallRequest instance with the contract address, caller context, and the hash of the call stack item. + */ + public toCallRequest() { + if (this.isEmpty()) { + return CallRequest.empty(); + } + + const callContext = this.publicInputs.callContext; + const callerContext = callContext.isDelegateCall + ? new CallerContext(callContext.msgSender, callContext.storageContractAddress) + : CallerContext.empty(); + // todo: populate side effect counters correctly + return new CallRequest(this.hash(), callContext.msgSender, callerContext, Fr.ZERO, Fr.ZERO); + } +} diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts index f1d2d822f5d..ab415ed487e 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.test.ts @@ -37,4 +37,13 @@ describe('PrivateCircuitPublicInputs', () => { const hash = target.hash(); expect(hash).toMatchSnapshot(); }); + + it('computes empty inputs hash', () => { + const inputs = PrivateCircuitPublicInputs.empty(); + const hash = inputs.hash(); + expect(hash).toMatchSnapshot(); + + // Value used in empty_hash test in private_circuit_public_inputs.nr + // console.log("hash", hash.toString()); + }); }); diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index d0734feb7c1..c556fceb0f3 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -17,8 +17,10 @@ import { NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; +import { ContractDeploymentData } from '../structs/contract_deployment_data.js'; +import { Header } from '../structs/header.js'; +import { SideEffect, SideEffectLinkedToNoteHash } from '../structs/side_effects.js'; import { CallContext } from './call_context.js'; -import { ContractDeploymentData, Header, SideEffect, SideEffectLinkedToNoteHash } from './index.js'; import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; /** @@ -39,6 +41,10 @@ export class PrivateCircuitPublicInputs { * Return values of the corresponding function call. */ public returnValues: Tuple, + /** + * The side-effect high watermark of the irrevertible part of the function call. + */ + public metaHwm: Fr, /** * Read requests created by the corresponding function call. */ @@ -136,6 +142,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(CallContext), reader.readObject(Fr), reader.readArray(RETURN_VALUES_LENGTH, Fr), + reader.readObject(Fr), reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect), @@ -161,6 +168,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(CallContext), reader.readField(), reader.readFieldArray(RETURN_VALUES_LENGTH), + reader.readField(), reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect), @@ -189,6 +197,7 @@ export class PrivateCircuitPublicInputs { CallContext.empty(), Fr.ZERO, makeTuple(RETURN_VALUES_LENGTH, Fr.zero), + Fr.ZERO, makeTuple(MAX_READ_REQUESTS_PER_CALL, SideEffect.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), makeTuple(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect.empty), @@ -217,6 +226,7 @@ export class PrivateCircuitPublicInputs { this.callContext.isEmpty() && this.argsHash.isZero() && isZeroArray(this.returnValues) && + this.metaHwm.isZero() && isEmptyArray(this.readRequests) && isEmptyArray(this.nullifierKeyValidationRequests) && isEmptyArray(this.newCommitments) && @@ -245,6 +255,7 @@ export class PrivateCircuitPublicInputs { fields.callContext, fields.argsHash, fields.returnValues, + fields.metaHwm, fields.readRequests, fields.nullifierKeyValidationRequests, fields.newCommitments, diff --git a/yarn-project/circuits.js/src/structs/public_call_request.ts b/yarn-project/circuits.js/src/structs/public_call_request.ts index ac5153aaa5f..8516081362a 100644 --- a/yarn-project/circuits.js/src/structs/public_call_request.ts +++ b/yarn-project/circuits.js/src/structs/public_call_request.ts @@ -1,18 +1,15 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; import { computeVarArgsHash } from '../abis/abis.js'; -import { CallerContext } from './call_request.js'; -import { - AztecAddress, - CallContext, - CallRequest, - Fr, - FunctionData, - PublicCallStackItem, - PublicCircuitPublicInputs, - Vector, -} from './index.js'; +import { CallContext } from './call_context.js'; +import { CallRequest, CallerContext } from './call_request.js'; +import { FunctionData } from './function_data.js'; +import { PublicCallStackItem } from './public_call_stack_item.js'; +import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; +import { Vector } from './shared.js'; /** * Represents a request to call a public function from a private function. Serialization is diff --git a/yarn-project/circuits.js/src/structs/call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts similarity index 50% rename from yarn-project/circuits.js/src/structs/call_stack_item.test.ts rename to yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts index 0a483a35699..028d3980fda 100644 --- a/yarn-project/circuits.js/src/structs/call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts @@ -1,28 +1,28 @@ -import { makePrivateCallStackItem } from '../tests/factories.js'; -import { PrivateCallStackItem } from './call_stack_item.js'; +import { makePublicCallStackItem } from '../tests/factories.js'; +import { PublicCallStackItem } from './public_call_stack_item.js'; -describe('PrivateCallStackItem', () => { +describe('PublicCallStackItem', () => { it('serializes to buffer and deserializes it back', () => { const randomInt = Math.floor(Math.random() * 1000); - const expected = makePrivateCallStackItem(randomInt); + const expected = makePublicCallStackItem(randomInt); const buffer = expected.toBuffer(); - const res = PrivateCallStackItem.fromBuffer(buffer); + const res = PublicCallStackItem.fromBuffer(buffer); expect(res).toEqual(expected); }); it('serializes to field array and deserializes it back', () => { const randomInt = Math.floor(Math.random() * 1000); - const expected = makePrivateCallStackItem(randomInt); + const expected = makePublicCallStackItem(randomInt); const fieldArray = expected.toFields(); - const res = PrivateCallStackItem.fromFields(fieldArray); + const res = PublicCallStackItem.fromFields(fieldArray); expect(res).toEqual(expected); }); it('computes hash', () => { const seed = 9870243; - const PrivateCallStackItem = makePrivateCallStackItem(seed); - const hash = PrivateCallStackItem.hash(); + const item = makePublicCallStackItem(seed); + const hash = item.hash(); expect(hash).toMatchSnapshot(); }); }); diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts new file mode 100644 index 00000000000..9a4337f3e46 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.ts @@ -0,0 +1,113 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { computePublicCallStackItemHash } from '../abis/abis.js'; +import { CallRequest, CallerContext } from './call_request.js'; +import { FunctionData } from './function_data.js'; +import { PublicCircuitPublicInputs } from './public_circuit_public_inputs.js'; + +/** + * Call stack item on a public call. + */ +export class PublicCallStackItem { + constructor( + /** + * Address of the contract on which the function is invoked. + */ + public contractAddress: AztecAddress, + /** + * Data identifying the function being called. + */ + public functionData: FunctionData, + /** + * Public inputs to the public kernel circuit. + */ + public publicInputs: PublicCircuitPublicInputs, + /** + * Whether the current callstack item should be considered a public fn execution request. + */ + public isExecutionRequest: boolean, + ) {} + + static getFields(fields: FieldsOf) { + return [fields.contractAddress, fields.functionData, fields.publicInputs, fields.isExecutionRequest] as const; + } + + toBuffer() { + return serializeToBuffer(...PublicCallStackItem.getFields(this)); + } + + toFields(): Fr[] { + return serializeToFields(...PublicCallStackItem.getFields(this)); + } + + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer(buffer: Buffer | BufferReader): PublicCallStackItem { + const reader = BufferReader.asReader(buffer); + return new PublicCallStackItem( + reader.readObject(AztecAddress), + reader.readObject(FunctionData), + reader.readObject(PublicCircuitPublicInputs), + reader.readBoolean(), + ); + } + + static fromFields(fields: Fr[] | FieldReader): PublicCallStackItem { + const reader = FieldReader.asReader(fields); + + const contractAddress = AztecAddress.fromFields(reader); + const functionData = FunctionData.fromFields(reader); + const publicInputs = PublicCircuitPublicInputs.fromFields(reader); + const isExecutionRequest = reader.readBoolean(); + + return new PublicCallStackItem(contractAddress, functionData, publicInputs, isExecutionRequest); + } + + /** + * Returns a new instance of PublicCallStackItem with zero contract address, function data and public inputs. + * @returns A new instance of PublicCallStackItem with zero contract address, function data and public inputs. + */ + public static empty(): PublicCallStackItem { + return new PublicCallStackItem( + AztecAddress.ZERO, + FunctionData.empty({ isPrivate: false }), + PublicCircuitPublicInputs.empty(), + false, + ); + } + + isEmpty() { + return this.contractAddress.isZero() && this.functionData.isEmpty() && this.publicInputs.isEmpty(); + } + + /** + * Computes this call stack item hash. + * @returns Hash. + */ + public hash() { + return computePublicCallStackItemHash(this); + } + + /** + * Creates a new CallRequest with values of the calling contract. + * @returns A CallRequest instance with the contract address, caller context, and the hash of the call stack item. + */ + public toCallRequest() { + if (this.isEmpty()) { + return CallRequest.empty(); + } + + const callContext = this.publicInputs.callContext; + const callerContext = callContext.isDelegateCall + ? new CallerContext(callContext.msgSender, callContext.storageContractAddress) + : CallerContext.empty(); + // todo: populate side effect counters correctly + return new CallRequest(this.hash(), callContext.msgSender, callerContext, Fr.ZERO, Fr.ZERO); + } +} diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index 7165200a87b..143e5f55163 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -3,7 +3,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { isArrayEmpty } from '@aztec/foundation/collection'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { FieldReader, Tuple, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, Tuple, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; import { @@ -18,13 +18,10 @@ import { RETURN_VALUES_LENGTH, } from '../constants.gen.js'; import { CallContext } from './call_context.js'; -import { - ContractStorageRead, - ContractStorageUpdateRequest, - Header, - SideEffect, - SideEffectLinkedToNoteHash, -} from './index.js'; +import { ContractStorageRead } from './contract_storage_read.js'; +import { ContractStorageUpdateRequest } from './contract_storage_update_request.js'; +import { Header } from './header.js'; +import { SideEffect, SideEffectLinkedToNoteHash } from './side_effects.js'; /** * Public inputs to a public circuit. @@ -178,40 +175,47 @@ export class PublicCircuitPublicInputs { return serializeToFields(...PublicCircuitPublicInputs.getFields(this)); } + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer(buffer: Buffer | BufferReader): PublicCircuitPublicInputs { + const reader = BufferReader.asReader(buffer); + return new PublicCircuitPublicInputs( + reader.readObject(CallContext), + reader.readObject(Fr), + reader.readArray(RETURN_VALUES_LENGTH, Fr), + reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, ContractStorageUpdateRequest), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_CALL, ContractStorageRead), + reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, Fr), + reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect), + reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash), + reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, Fr), + reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readObject(Fr), + reader.readObject(Header), + reader.readObject(AztecAddress), + ); + } + static fromFields(fields: Fr[] | FieldReader): PublicCircuitPublicInputs { const reader = FieldReader.asReader(fields); - const callContext = CallContext.fromFields(reader); - const argsHash = reader.readField(); - const returnValues = reader.readFieldArray(RETURN_VALUES_LENGTH); - const contractStorageUpdateRequests = reader.readArray( - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - ContractStorageUpdateRequest, - ); - const contractStorageReads = reader.readArray(MAX_PUBLIC_DATA_READS_PER_CALL, ContractStorageRead); - const publicCallStackHashes = reader.readFieldArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL); - const newCommitments = reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect); - const newNullifiers = reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash); - const newL2ToL1Msgs = reader.readFieldArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL); - const unencryptedLogsHash = reader.readFieldArray(NUM_FIELDS_PER_SHA256); - const unencryptedLogPreimagesLength = reader.readField(); - const historicalHeader = Header.fromFields(reader); - const proverAddress = AztecAddress.fromFields(reader); - return new PublicCircuitPublicInputs( - callContext, - argsHash, - returnValues, - contractStorageUpdateRequests, - contractStorageReads, - publicCallStackHashes, - newCommitments, - newNullifiers, - newL2ToL1Msgs, - unencryptedLogsHash, - unencryptedLogPreimagesLength, - historicalHeader, - proverAddress, + CallContext.fromFields(reader), + reader.readField(), + reader.readFieldArray(RETURN_VALUES_LENGTH), + reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, ContractStorageUpdateRequest), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_CALL, ContractStorageRead), + reader.readFieldArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL), + reader.readArray(MAX_NEW_COMMITMENTS_PER_CALL, SideEffect), + reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash), + reader.readFieldArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL), + reader.readFieldArray(NUM_FIELDS_PER_SHA256), + reader.readField(), + Header.fromFields(reader), + AztecAddress.fromFields(reader), ); } diff --git a/yarn-project/circuits.js/src/structs/side_effects.ts b/yarn-project/circuits.js/src/structs/side_effects.ts index 25b3df86a88..88ca402dd5e 100644 --- a/yarn-project/circuits.js/src/structs/side_effects.ts +++ b/yarn-project/circuits.js/src/structs/side_effects.ts @@ -1,7 +1,6 @@ +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { Fr } from './index.js'; - /** * Essential members and functions of all SideEffect variants */ diff --git a/yarn-project/circuits.js/src/structs/tx_context.ts b/yarn-project/circuits.js/src/structs/tx_context.ts index 07becc7f95e..77b35cfd367 100644 --- a/yarn-project/circuits.js/src/structs/tx_context.ts +++ b/yarn-project/circuits.js/src/structs/tx_context.ts @@ -1,7 +1,8 @@ +import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { FieldsOf } from '@aztec/foundation/types'; -import { ContractDeploymentData, Fr } from './index.js'; +import { ContractDeploymentData } from '../structs/contract_deployment_data.js'; /** * Transaction context. diff --git a/yarn-project/circuits.js/src/structs/verification_key.ts b/yarn-project/circuits.js/src/structs/verification_key.ts index 1e397cec8ce..b89d0d0b4bf 100644 --- a/yarn-project/circuits.js/src/structs/verification_key.ts +++ b/yarn-project/circuits.js/src/structs/verification_key.ts @@ -1,7 +1,7 @@ import { times } from '@aztec/foundation/collection'; +import { Fq } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { Fq } from './index.js'; import { CircuitType } from './shared.js'; /** diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 3b76b5d768a..6951e8ced19 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -3,11 +3,13 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { numToUInt32BE } from '@aztec/foundation/serialize'; +import { ContractClassPublic, PrivateFunction, PublicFunction } from '@aztec/types/contracts'; import { SchnorrSignature } from '../barretenberg/index.js'; import { ARCHIVE_HEIGHT, ARGS_LENGTH, + AccumulatedMetaData, AggregationObject, AppendOnlyTreeSnapshot, BaseOrMergeRollupPublicInputs, @@ -36,18 +38,20 @@ import { L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, + MAX_NEW_COMMITMENTS_PER_TX_META, MAX_NEW_CONTRACTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX_META, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, @@ -66,7 +70,6 @@ import { NullifierKeyValidationRequest, NullifierKeyValidationRequestContext, NullifierLeafPreimage, - OptionallyRevealedData, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, PUBLIC_DATA_TREE_HEIGHT, PartialStateReference, @@ -104,6 +107,9 @@ import { VK_TREE_HEIGHT, VerificationKey, WitnessedPublicCallData, + computeContractClassId, + computePublicBytecodeCommitment, + packBytecode, } from '../index.js'; import { GlobalVariables } from '../structs/global_variables.js'; import { Header, NUM_BYTES_PER_SHA256 } from '../structs/header.js'; @@ -238,7 +244,6 @@ export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulated const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( - makeAggregationObject(seed), tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), tupleGenerator( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, @@ -255,7 +260,6 @@ export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulated fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_NEW_CONTRACTS_PER_TX, makeNewContractData, seed + 0xb00), - tupleGenerator(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, makeOptionallyRevealedData, seed + 0xc00), tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), tupleGenerator(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); @@ -270,7 +274,6 @@ export function makeFinalAccumulatedData(seed = 1, full = false): FinalAccumulat const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new FinalAccumulatedData( - makeAggregationObject(seed), tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX, sideEffectFromNumber, seed + 0x100), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x200), tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), @@ -281,7 +284,21 @@ export function makeFinalAccumulatedData(seed = 1, full = false): FinalAccumulat fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_NEW_CONTRACTS_PER_TX, makeNewContractData, seed + 0xb00), - tupleGenerator(MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, makeOptionallyRevealedData, seed + 0xc00), + ); +} + +/** + * Creates arbitrary accumulated data for a Tx's meta phase. + * @param seed - The seed to use for generating the data. + * @returns An instance of AccumulatedMetaData. + */ +export function makeAccumulatedMetaData(seed = 1, full = false): AccumulatedMetaData { + const tupleGenerator = full ? makeTuple : makeHalfFullTuple; + + return new AccumulatedMetaData( + tupleGenerator(MAX_NEW_COMMITMENTS_PER_TX_META, sideEffectFromNumber, seed + 0x101), + tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX_META, sideEffectLinkedFromNumber, seed + 0x201), + tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, makeCallRequest, seed + 0x501), ); } @@ -294,24 +311,6 @@ export function makeNewContractData(seed = 1): NewContractData { return new NewContractData(makeAztecAddress(seed), makeEthAddress(seed + 1), fr(seed + 2)); } -/** - * Creates arbitrary optionally revealed data. - * @param seed - The seed to use for generating the optionally revealed data. - * @returns An optionally revealed data. - */ -export function makeOptionallyRevealedData(seed = 1): OptionallyRevealedData { - return new OptionallyRevealedData( - fr(seed), - new FunctionData(makeSelector(seed + 1), false, true, true), - fr(seed + 2), - makeEthAddress(seed + 3), - true, - false, - true, - false, - ); -} - /** * Creates arbitrary aggregation object. * @param seed - The seed to use for generating the aggregation object. @@ -382,6 +381,8 @@ export function makePublicCircuitPublicInputs( */ export function makeKernelPublicInputs(seed = 1, fullAccumulatedData = true): KernelCircuitPublicInputs { return new KernelCircuitPublicInputs( + makeAggregationObject(seed), + fr(seed + 0x100), makeAccumulatedData(seed, fullAccumulatedData), makeConstantData(seed + 0x100), true, @@ -394,7 +395,13 @@ export function makeKernelPublicInputs(seed = 1, fullAccumulatedData = true): Ke * @returns Final ordering kernel circuit public inputs. */ export function makePrivateKernelPublicInputsFinal(seed = 1): PrivateKernelPublicInputsFinal { - return new PrivateKernelPublicInputsFinal(makeFinalAccumulatedData(seed, true), makeConstantData(seed + 0x100)); + return new PrivateKernelPublicInputsFinal( + makeAggregationObject(seed), + fr(seed + 0x100), + makeAccumulatedMetaData(seed, true), + makeFinalAccumulatedData(seed, true), + makeConstantData(seed + 0x100), + ); } /** @@ -689,7 +696,6 @@ export function makePrivateCallStackItem(seed = 1): PrivateCallStackItem { makeAztecAddress(seed), new FunctionData(makeSelector(seed + 0x1), false, true, true), makePrivateCircuitPublicInputs(seed + 0x10), - false, ); } @@ -712,6 +718,7 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn ), argsHash: fr(seed + 0x100), returnValues: makeTuple(RETURN_VALUES_LENGTH, fr, seed + 0x200), + metaHwm: fr(0), readRequests: makeTuple(MAX_READ_REQUESTS_PER_CALL, sideEffectFromNumber, seed + 0x300), nullifierKeyValidationRequests: makeTuple( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, @@ -759,9 +766,23 @@ export function makeContractDeploymentData(seed = 1) { */ export function makeGlobalVariables(seed = 1, blockNumber: number | undefined = undefined): GlobalVariables { if (blockNumber !== undefined) { - return new GlobalVariables(fr(seed), fr(seed + 1), fr(blockNumber), fr(seed + 3)); + return new GlobalVariables( + fr(seed), + fr(seed + 1), + fr(blockNumber), + fr(seed + 3), + EthAddress.fromField(fr(seed + 4)), + AztecAddress.fromField(fr(seed + 5)), + ); } - return new GlobalVariables(fr(seed), fr(seed + 1), fr(seed + 2), fr(seed + 3)); + return new GlobalVariables( + fr(seed), + fr(seed + 1), + fr(seed + 2), + fr(seed + 3), + EthAddress.fromField(fr(seed + 4)), + AztecAddress.fromField(fr(seed + 5)), + ); } /** @@ -1072,6 +1093,40 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { }); } +export function makeContractClassPublic(seed = 0): ContractClassPublic { + const artifactHash = fr(seed + 1); + const publicFunctions = makeTuple(3, makeContractClassPublicFunction, seed + 2); + const privateFunctionsRoot = fr(seed + 3); + const packedBytecode = packBytecode(publicFunctions); + const publicBytecodeCommitment = computePublicBytecodeCommitment(packedBytecode); + const id = computeContractClassId({ artifactHash, privateFunctionsRoot, publicBytecodeCommitment }); + return { + id, + artifactHash, + packedBytecode, + privateFunctionsRoot, + publicFunctions, + version: 1, + }; +} + +function makeContractClassPublicFunction(seed = 0): PublicFunction { + return { + selector: FunctionSelector.fromField(fr(seed + 1)), + bytecode: makeBytes(100, seed + 2), + isInternal: false, + }; +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function makeContractClassPrivateFunction(seed = 0): PrivateFunction { + return { + selector: FunctionSelector.fromField(fr(seed + 1)), + vkHash: fr(seed + 2), + isInternal: false, + }; +} + /** * TODO: Since the max value check is currently disabled this function is pointless. Should it be removed? * Test only. Easy to identify big endian field serialize. diff --git a/yarn-project/circuits.js/src/tests/fixtures.ts b/yarn-project/circuits.js/src/tests/fixtures.ts index 135bd6edbe5..ceb6611d394 100644 --- a/yarn-project/circuits.js/src/tests/fixtures.ts +++ b/yarn-project/circuits.js/src/tests/fixtures.ts @@ -6,8 +6,25 @@ import { readFileSync } from 'fs'; import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; +// Copied from the build output for the contract `Benchmarking` in noir-contracts export function getSampleContractArtifact(): ContractArtifact { - const path = resolve(dirname(fileURLToPath(import.meta.url)), '../../fixtures/Benchmarking.test.json'); + const path = getPathToFixture('Benchmarking.test.json'); const content = JSON.parse(readFileSync(path).toString()) as NoirCompiledContract; return loadContractArtifact(content); } + +// Copied from the test 'registers a new contract class' in end-to-end/src/e2e_deploy_contract.test.ts +export function getSampleContractClassRegisteredEventPayload(): Buffer { + const path = getPathToFixture('ContractClassRegisteredEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +// Copied from the test 'deploying a contract instance' in end-to-end/src/e2e_deploy_contract.test.ts +export function getSampleContractInstanceDeployedEventPayload(): Buffer { + const path = getPathToFixture('ContractInstanceDeployedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +function getPathToFixture(name: string) { + return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`); +} diff --git a/yarn-project/circuits.js/src/types/contract_function_dao.ts b/yarn-project/circuits.js/src/types/contract_function_dao.ts index 84675ecb65e..7d97ccda986 100644 --- a/yarn-project/circuits.js/src/types/contract_function_dao.ts +++ b/yarn-project/circuits.js/src/types/contract_function_dao.ts @@ -1,6 +1,4 @@ -import { FunctionArtifact } from '@aztec/foundation/abi'; - -import { FunctionSelector } from '../index.js'; +import { FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi'; /** * A contract function Data Access Object (DAO). diff --git a/yarn-project/circuits.js/src/types/deployment_info.ts b/yarn-project/circuits.js/src/types/deployment_info.ts index 2cc3b98ddc3..637bab821b9 100644 --- a/yarn-project/circuits.js/src/types/deployment_info.ts +++ b/yarn-project/circuits.js/src/types/deployment_info.ts @@ -1,4 +1,6 @@ -import { CompleteAddress, Fr } from '../index.js'; +import { Fr } from '@aztec/foundation/fields'; + +import { CompleteAddress } from '../structs/complete_address.js'; /** * Represents the data generated as part of contract deployment. diff --git a/yarn-project/cli/src/cmds/unbox.ts b/yarn-project/cli/src/cmds/unbox.ts index b1b6542b5e0..a04702d0e88 100644 --- a/yarn-project/cli/src/cmds/unbox.ts +++ b/yarn-project/cli/src/cmds/unbox.ts @@ -16,6 +16,7 @@ const resolutions: { [key: string]: string } = { '@aztec/bb.js': 'portal:.aztec-packages/barretenberg/ts', '@aztec/circuit-types': 'portal:.aztec-packages/yarn-project/circuit-types', '@aztec/ethereum': 'portal:.aztec-packages/yarn-project/ethereum', + '@aztec/protocol-contracts': 'portal:.aztec-packages/yarn-project/protocol-contracts', '@aztec/types': 'portal:.aztec-packages/yarn-project/types', }; @@ -71,6 +72,7 @@ function copyDependenciesToBox(dirName: string, destPath: string) { 'yarn-project/types', 'yarn-project/circuit-types', 'yarn-project/ethereum', + 'yarn-project/protocol-contracts', ].forEach(path => cpSync(dirName + '/../../../../' + path, destPath + '/.aztec-packages/' + path, { recursive: true, diff --git a/yarn-project/deploy_npm.sh b/yarn-project/deploy_npm.sh index 9132db974d0..ddbc1226be5 100755 --- a/yarn-project/deploy_npm.sh +++ b/yarn-project/deploy_npm.sh @@ -83,15 +83,17 @@ deploy_package foundation deploy_package types deploy_package circuits.js deploy_package circuit-types +deploy_package protocol-contracts deploy_package aztec.js deploy_package accounts deploy_package l1-artifacts deploy_package ethereum deploy_package noir-compiler deploy_package noir-contracts +deploy_package kv-store deploy_package merkle-tree deploy_package noir-protocol-circuits -deploy_package acir-simulator +deploy_package simulator deploy_package key-store deploy_package pxe deploy_package archiver diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index c03353a9a88..a99395be793 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -99,6 +99,8 @@ Rollup Address: 0x0dcd1bf9a1b36ce34237eeafef220932846bcd82 BenchmarkingContractArtifact CardGameContractArtifact ChildContractArtifact +ContractClassRegistererContractArtifact +ContractInstanceDeployerContractArtifact CounterContractArtifact DocsExampleContractArtifact EasyPrivateTokenContractArtifact diff --git a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts index d6f41b87384..9f462b241dc 100644 --- a/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_blacklist_token_contract.test.ts @@ -14,7 +14,7 @@ import { computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Pedersen, SparseTree, newTree } from '@aztec/merkle-tree'; import { SlowTreeContract, TokenBlacklistContract, TokenContract } from '@aztec/noir-contracts'; @@ -104,7 +104,7 @@ describe('e2e_blacklist_token_contract', () => { slowTree = await SlowTreeContract.deploy(wallets[0]).send().deployed(); const depth = 254; - slowUpdateTreeSimulator = await newTree(SparseTree, await AztecLmdbStore.openTmp(), new Pedersen(), 'test', depth); + slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', depth); const deployTx = TokenBlacklistContract.deploy(wallets[0], accounts[0], slowTree.address).send({}); const receipt = await deployTx.wait(); diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 645d2b4f325..9b5760759bd 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -147,7 +147,7 @@ describe('e2e_block_building', () => { it('drops tx with private nullifier already emitted from public on the same block', async () => { const secret = Fr.random(); - // See yarn-project/acir-simulator/src/public/index.test.ts 'Should be able to create a nullifier from the public context' + // See yarn-project/simulator/src/public/index.test.ts 'Should be able to create a nullifier from the public context' const emittedPublicNullifier = pedersenHash([new Fr(140), secret].map(a => a.toBuffer())); const calls = [ diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 83023b8505a..6dfc3d9e208 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -1,22 +1,36 @@ import { AztecAddress, + AztecNode, BatchCall, CompleteAddress, Contract, ContractArtifact, + ContractBase, + ContractClassWithId, ContractDeployer, + ContractInstanceWithAddress, DebugLogger, EthAddress, Fr, PXE, SignerlessWallet, + TxHash, TxStatus, Wallet, + getContractClassFromArtifact, getContractInstanceFromDeployParams, isContractDeployed, } from '@aztec/aztec.js'; +import { + broadcastPrivateFunction, + broadcastUnconstrainedFunction, + deployInstance, + registerContractClass, +} from '@aztec/aztec.js/deployment'; +import { ContractClassIdPreimage, Point, PublicKey } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/abis'; -import { StatefulTestContract } from '@aztec/noir-contracts'; +import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { ContractInstanceDeployerContract, StatefulTestContract } from '@aztec/noir-contracts'; import { TestContract, TestContractArtifact } from '@aztec/noir-contracts/Test'; import { TokenContractArtifact } from '@aztec/noir-contracts/Token'; import { SequencerClient } from '@aztec/sequencer-client'; @@ -29,13 +43,14 @@ describe('e2e_deploy_contract', () => { let logger: DebugLogger; let wallet: Wallet; let sequencer: SequencerClient | undefined; + let aztecNode: AztecNode; let teardown: () => Promise; - beforeEach(async () => { - ({ teardown, pxe, accounts, logger, wallet, sequencer } = await setup()); + beforeAll(async () => { + ({ teardown, pxe, accounts, logger, wallet, sequencer, aztecNode } = await setup()); }, 100_000); - afterEach(() => teardown()); + afterAll(() => teardown()); /** * Milestone 1.1. @@ -240,6 +255,109 @@ describe('e2e_deploy_contract', () => { expect(await contracts[0].methods.summed_values(owner).view()).toEqual(42n); expect(await contracts[1].methods.summed_values(owner).view()).toEqual(52n); }); + + // Tests registering a new contract class on a node and then deploying an instance. + // These tests look scary, but don't fret: all this hodgepodge of calls will be hidden + // behind a much nicer API in the near future as part of #4080. + describe('registering a contract class', () => { + let artifact: ContractArtifact; + let contractClass: ContractClassWithId & ContractClassIdPreimage; + + beforeAll(async () => { + artifact = StatefulTestContract.artifact; + await registerContractClass(wallet, artifact).send().wait(); + contractClass = getContractClassFromArtifact(artifact); + }, 60_000); + + it('registers the contract class on the node', async () => { + const registeredClass = await aztecNode.getContractClass(contractClass.id); + expect(registeredClass).toBeDefined(); + expect(registeredClass!.artifactHash.toString()).toEqual(contractClass.artifactHash.toString()); + expect(registeredClass!.privateFunctionsRoot.toString()).toEqual(contractClass.privateFunctionsRoot.toString()); + expect(registeredClass!.packedBytecode.toString('hex')).toEqual(contractClass.packedBytecode.toString('hex')); + expect(registeredClass!.publicFunctions).toEqual(contractClass.publicFunctions); + expect(registeredClass!.privateFunctions).toEqual([]); + }); + + it('broadcasts a private function', async () => { + const selector = contractClass.privateFunctions[0].selector; + await broadcastPrivateFunction(wallet, artifact, selector).send().wait(); + // TODO(#4428): Test that these functions are captured by the node and made available when + // requesting the corresponding contract class. + }, 60_000); + + it('broadcasts an unconstrained function', async () => { + const functionArtifact = artifact.functions.find(fn => fn.functionType === FunctionType.UNCONSTRAINED)!; + const selector = FunctionSelector.fromNameAndParameters(functionArtifact); + await broadcastUnconstrainedFunction(wallet, artifact, selector).send().wait(); + // TODO(#4428): Test that these functions are captured by the node and made available when + // requesting the corresponding contract class. + }, 60_000); + + describe('deploying a contract instance', () => { + let instance: ContractInstanceWithAddress; + let deployer: ContractInstanceDeployerContract; + let deployTxHash: TxHash; + let initArgs: StatefulContractCtorArgs; + let publicKey: PublicKey; + + beforeAll(async () => { + initArgs = [accounts[0].address, 42]; + deployer = await registerContract(wallet, ContractInstanceDeployerContract, [], { salt: new Fr(1) }); + + const salt = Fr.random(); + const portalAddress = EthAddress.random(); + publicKey = Point.random(); + + instance = getContractInstanceFromDeployParams(artifact, initArgs, salt, publicKey, portalAddress); + const { address, contractClassId } = instance; + logger(`Deploying contract instance at ${address.toString()} class id ${contractClassId.toString()}`); + + const tx = await deployInstance(wallet, instance).send().wait(); + deployTxHash = tx.txHash; + }); + + it('emits deployment log', async () => { + const logs = await pxe.getUnencryptedLogs({ txHash: deployTxHash }); + const deployedLog = logs.logs[0].log; + expect(deployedLog.contractAddress).toEqual(deployer.address); + }); + + it('stores contract instance in the aztec node', async () => { + const deployed = await aztecNode.getContract(instance.address); + expect(deployed).toBeDefined(); + expect(deployed!.address).toEqual(instance.address); + expect(deployed!.contractClassId).toEqual(contractClass.id); + expect(deployed!.initializationHash).toEqual(instance.initializationHash); + expect(deployed!.portalContractAddress).toEqual(instance.portalContractAddress); + expect(deployed!.publicKeysHash).toEqual(instance.publicKeysHash); + expect(deployed!.salt).toEqual(instance.salt); + }); + + it('calls a public function on the deployed instance', async () => { + // TODO(@spalladino) We should **not** need the whole instance, including initArgs and salt, + // in order to interact with a public function for the contract. We may even not need + // all of it for running a private function. Consider removing `instance` as a required + // field in the aztec.js `Contract` class, maybe we can replace it with just the partialAddress. + // Not just that, but this instance has been broadcasted, so the pxe should be able to get + // its information from the node directly, excluding private functions, but it's ok because + // we are not going to run those - but this may require registering "partial" contracts in the pxe. + // Anyway, when we implement that, we should be able to replace this `registerContract` with + // a simpler `Contract.at(instance.address, wallet)`. + const registered = await registerContract(wallet, StatefulTestContract, initArgs, { + salt: instance.salt, + portalAddress: instance.portalContractAddress, + publicKey, + }); + expect(registered.address).toEqual(instance.address); + const contract = await StatefulTestContract.at(instance.address, wallet); + const whom = AztecAddress.random(); + await contract.methods.increment_public_value(whom, 10).send({ skipPublicSimulation: true }).wait(); + const stored = await contract.methods.get_public_value(whom).view(); + expect(stored).toEqual(10n); + }); + }); + }); }); type StatefulContractCtorArgs = Parameters; @@ -250,13 +368,19 @@ async function registerRandomAccount(pxe: PXE): Promise { return owner.address; } -type ContractArtifactClass = { - at(address: AztecAddress, wallet: Wallet): Promise; +type ContractArtifactClass = { + at(address: AztecAddress, wallet: Wallet): Promise; artifact: ContractArtifact; }; -async function registerContract(wallet: Wallet, contractArtifact: ContractArtifactClass, args: any[] = []) { - const instance = getContractInstanceFromDeployParams(contractArtifact.artifact, args); +async function registerContract( + wallet: Wallet, + contractArtifact: ContractArtifactClass, + args: any[] = [], + opts: { salt?: Fr; publicKey?: Point; portalAddress?: EthAddress } = {}, +): Promise { + const { salt, publicKey, portalAddress } = opts; + const instance = getContractInstanceFromDeployParams(contractArtifact.artifact, args, salt, publicKey, portalAddress); await wallet.addContracts([{ artifact: contractArtifact.artifact, instance }]); return contractArtifact.at(instance.address, wallet); } diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index 87821e95d11..459fddef998 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -52,59 +52,101 @@ describe('e2e_inclusion_proofs_contract', () => { owner = accounts[0].address; }); - it('proves note existence and its nullifier non-existence and nullifier non-existence failure case', async () => { + describe('proves note existence and its nullifier non-existence and nullifier non-existence failure case', () => { // Owner of a note let noteCreationBlockNumber: number; - { + let newCommitments, visibleNotes: any; + const value = 100n; + let validNoteBlockNumber: any; + + it('should return the correct values for creating a note', async () => { // Create a note - const value = 100n; const receipt = await contract.methods.create_note(owner, value).send().wait({ debug: true }); noteCreationBlockNumber = receipt.blockNumber!; - const { newCommitments, visibleNotes } = receipt.debugInfo!; + ({ newCommitments, visibleNotes } = receipt.debugInfo!); + }); + it('should return the correct values for creating a note', () => { expect(newCommitments.length).toBe(1); expect(visibleNotes.length).toBe(1); const [receivedValue, receivedOwner, _randomness] = visibleNotes[0].note.items; expect(receivedValue.toBigInt()).toBe(value); expect(receivedOwner).toEqual(owner.toField()); - } + }); - { + it('should not throw because the note is included', async () => { // Prove note inclusion in a given block. - const ignoredCommitment = 0; // Not ignored only when the note doesn't exist - await contract.methods - .test_note_inclusion_proof(owner, noteCreationBlockNumber, ignoredCommitment) - .send() - .wait(); - } + await contract.methods.test_note_inclusion(owner, true, noteCreationBlockNumber, false).send().wait(); - { - // Prove that the note has not been nullified + await contract.methods.test_note_inclusion(owner, false, 0n, false).send().wait(); + }); + + it('should not throw because the note is not nullified', async () => { + // Prove that the note has not been nullified with block_number // TODO(#3535): Prove the nullifier non-inclusion at older block to test archival node. This is currently not // possible because of issue https://github.com/AztecProtocol/aztec-packages/issues/3535 const blockNumber = await pxe.getBlockNumber(); - const ignoredNullifier = 0; // Not ignored only when the note doesn't exist - await contract.methods.test_nullifier_non_inclusion_proof(owner, blockNumber, ignoredNullifier).send().wait(); - } - - { + await contract.methods.test_note_not_nullified(owner, true, blockNumber, false).send().wait(); + await contract.methods.test_note_not_nullified(owner, false, 0n, false).send().wait(); + }); + + it('should not throw because is both included, not nullified, and therefore valid', async () => { + validNoteBlockNumber = await pxe.getBlockNumber(); + await contract.methods.test_note_validity(owner, true, validNoteBlockNumber, false).send().wait(); + await contract.methods.test_note_validity(owner, false, 0n, false).send().wait(); + }); + + describe('we will test the vailure case by nullifying a note', () => { + let receipt: any; + let currentBlockNumber: any; // We test the failure case now --> The proof should fail when the nullifier already exists - const receipt = await contract.methods.nullify_note(owner).send().wait({ debug: true }); - const { newNullifiers } = receipt.debugInfo!; - expect(newNullifiers.length).toBe(2); + it('nullifies a note and grabs block number', async () => { + receipt = await contract.methods.nullify_note(owner).send().wait({ debug: true }); + currentBlockNumber = await pxe.getBlockNumber(); + + const { newNullifiers } = receipt!.debugInfo!; + expect(newNullifiers.length).toBe(2); + // const nullifier = newNullifiers[1]; + }); - const blockNumber = await pxe.getBlockNumber(); - const nullifier = newNullifiers[1]; // Note: getLowNullifierMembershipWitness returns the membership witness of the nullifier itself and not // the low nullifier when the nullifier already exists in the tree and for this reason the execution fails // on low_nullifier.value < nullifier.value check. - await expect( - contract.methods.test_nullifier_non_inclusion_proof(owner, blockNumber, nullifier).send().wait(), - ).rejects.toThrowError( - /Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed/, - ); - } + it('should throw when testing if note is not nullified at the current block', async () => { + await expect( + contract.methods.test_note_not_nullified(owner, true, currentBlockNumber, true).send().wait(), + ).rejects.toThrow( + /Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed/, + ); + await expect(contract.methods.test_note_not_nullified(owner, false, 0n, true).send().wait()).rejects.toThrow( + /Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed/, + ); + }); + + it('should not throw when we test inclusion of nullified note', async () => { + await contract.methods.test_note_inclusion(owner, true, noteCreationBlockNumber, true).send().wait(); + + await contract.methods.test_note_inclusion(owner, false, 0n, true).send().wait(); + }); + + it('should throw when we test validity', async () => { + const blockNumber = await pxe.getBlockNumber(); + await expect( + contract.methods.test_note_validity(owner, true, blockNumber, true).send().wait(), + ).rejects.toThrow( + /Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed/, + ); + await expect(contract.methods.test_note_validity(owner, false, 0n, true).send().wait()).rejects.toThrow( + /Proving nullifier non-inclusion failed: low_nullifier.value < nullifier.value check failed/, + ); + }); + + it('should not throw because the note was not nullified yet at validNoteBlockNumber', async () => { + await contract.methods.test_note_not_nullified(owner, true, validNoteBlockNumber, true).send().wait(); + await contract.methods.test_note_validity(owner, true, validNoteBlockNumber, true).send().wait(); + }); + }); }); it('proves note validity (note commitment inclusion and nullifier non-inclusion)', async () => { @@ -128,21 +170,26 @@ describe('e2e_inclusion_proofs_contract', () => { { // Prove note validity - await contract.methods.test_note_validity_proof(owner, noteCreationBlockNumber).send().wait(); + await contract.methods.test_note_validity(owner, true, noteCreationBlockNumber, false).send().wait(); + await contract.methods.test_note_validity(owner, false, 0n, false).send().wait(); } }); it('note existence failure case', async () => { // Owner of a note - ignored in the contract since the note won't be found and the spare random note commitment // will be used instead - const owner = AztecAddress.random(); + const owner = AztecAddress.fromField(new Fr(88n)); // Choose random block number between deployment and current block number to test archival node const blockNumber = await getRandomBlockNumberSinceDeployment(); - const randomNoteCommitment = Fr.random(); + await expect( - contract.methods.test_note_inclusion_proof(owner, blockNumber, randomNoteCommitment).send().wait(), - ).rejects.toThrow(`Leaf value: ${randomNoteCommitment.toString()} not found in NOTE_HASH_TREE`); + contract.methods.test_note_inclusion_fail_case(owner, true, blockNumber).send().wait(), + ).rejects.toThrow(/Leaf value: .* not found in NOTE_HASH_TREE/); + + await expect(contract.methods.test_note_inclusion_fail_case(owner, false, 0n).send().wait()).rejects.toThrow( + /Leaf value: .* not found in NOTE_HASH_TREE/, + ); }); }); @@ -151,7 +198,8 @@ describe('e2e_inclusion_proofs_contract', () => { // Choose random block number between deployment and current block number to test archival node const blockNumber = await getRandomBlockNumberSinceDeployment(); - await contract.methods.test_public_value_inclusion_proof(publicValue, blockNumber).send().wait(); + await contract.methods.test_public_value_inclusion(publicValue, true, blockNumber).send().wait(); + await contract.methods.test_public_value_inclusion(publicValue, false, 0n).send().wait(); }); it('public value existence failure case', async () => { @@ -159,13 +207,16 @@ describe('e2e_inclusion_proofs_contract', () => { const blockNumber = await getRandomBlockNumber(); const randomPublicValue = Fr.random(); await expect( - contract.methods.test_public_value_inclusion_proof(randomPublicValue, blockNumber).send().wait(), + contract.methods.test_public_value_inclusion(randomPublicValue, true, blockNumber).send().wait(), + ).rejects.toThrow('Public value does not match the witness'); + await expect( + contract.methods.test_public_value_inclusion(randomPublicValue, false, 0n).send().wait(), ).rejects.toThrow('Public value does not match the witness'); }); it('proves existence of uninitialized public value', async () => { const blockNumber = await getRandomBlockNumber(); - await contract.methods.test_public_unused_value_inclusion_proof(blockNumber).send().wait(); + await contract.methods.test_public_unused_value_inclusion(blockNumber).send().wait(); }); }); @@ -176,7 +227,8 @@ describe('e2e_inclusion_proofs_contract', () => { const block = await pxe.getBlock(blockNumber); const nullifier = block?.newNullifiers[0]; - await contract.methods.test_nullifier_inclusion_proof(nullifier!, blockNumber).send().wait(); + await contract.methods.test_nullifier_inclusion(nullifier!, true, blockNumber).send().wait(); + await contract.methods.test_nullifier_inclusion(nullifier!, false, 0n).send().wait(); }); it('nullifier existence failure case', async () => { @@ -185,8 +237,12 @@ describe('e2e_inclusion_proofs_contract', () => { const randomNullifier = Fr.random(); await expect( - contract.methods.test_nullifier_inclusion_proof(randomNullifier, blockNumber).send().wait(), + contract.methods.test_nullifier_inclusion(randomNullifier, true, blockNumber).send().wait(), ).rejects.toThrow(`Low nullifier witness not found for nullifier ${randomNullifier.toString()} at block`); + + await expect(contract.methods.test_nullifier_inclusion(randomNullifier, false, 0n).send().wait()).rejects.toThrow( + `Low nullifier witness not found for nullifier ${randomNullifier.toString()} at block`, + ); }); }); @@ -221,7 +277,7 @@ describe('e2e_inclusion_proofs_contract', () => { // Note: We pass in preimage of AztecAddress instead of just AztecAddress in order for the contract to be able to // test that the contract was deployed with correct constructor parameters. await contract.methods - .test_contract_inclusion_proof( + .test_contract_inclusion( publicKey, contractAddressSalt, contractClassId, @@ -242,7 +298,7 @@ describe('e2e_inclusion_proofs_contract', () => { await expect( contract.methods - .test_contract_inclusion_proof( + .test_contract_inclusion( publicKey, contractAddressSalt, contractClassId, diff --git a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts index 21693a62aea..32531fc15c3 100644 --- a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts +++ b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts @@ -1,6 +1,6 @@ /* eslint-disable camelcase */ import { CheatCodes, DebugLogger, Fr, Wallet } from '@aztec/aztec.js'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Pedersen, SparseTree, newTree } from '@aztec/merkle-tree'; import { SlowTreeContract } from '@aztec/noir-contracts/SlowTree'; @@ -23,13 +23,7 @@ describe('e2e_slow_tree', () => { it('Messing around with noir slow tree', async () => { const depth = 254; - const slowUpdateTreeSimulator = await newTree( - SparseTree, - await AztecLmdbStore.openTmp(), - new Pedersen(), - 'test', - depth, - ); + const slowUpdateTreeSimulator = await newTree(SparseTree, openTmpStore(), new Pedersen(), 'test', depth); const getMembershipProof = async (index: bigint, includeUncommitted: boolean) => { return { index, diff --git a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts index 25e501b8fdb..fd673178798 100644 --- a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts @@ -10,7 +10,7 @@ import { Wallet, computeMessageSecretHash, } from '@aztec/aztec.js'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; import { TokenContract } from '@aztec/noir-contracts/Token'; import { Chain, HttpTransport, PublicClient } from 'viem'; @@ -43,7 +43,9 @@ describe('archiver integration with l1 to l2 messages', () => { config.archiverPollingIntervalMS = 100; archiver = await Archiver.createAndSync( { ...config, l1Contracts: deployL1ContractsValues.l1ContractAddresses }, - new KVArchiverDataStore(await AztecLmdbStore.open(deployL1ContractsValues.l1ContractAddresses.rollupAddress)), + new KVArchiverDataStore( + await initStoreForRollup(openTmpStore(), deployL1ContractsValues.l1ContractAddresses.rollupAddress), + ), ); const walletClient = deployL1ContractsValues.walletClient; diff --git a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts index f147fccfd4b..01d0e5a240b 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -10,6 +10,7 @@ import { to2Fields, } from '@aztec/aztec.js'; import { + EthAddress, Header, KernelCircuitPublicInputs, MAX_NEW_COMMITMENTS_PER_TX, @@ -29,7 +30,7 @@ import { } from '@aztec/circuits.js/factories'; import { createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { EmptyRollupProver, @@ -98,6 +99,9 @@ describe('L1Publisher integration', () => { const chainId = createEthereumChain(config.rpcUrl, config.apiKey).chainInfo.id; + let coinbase: EthAddress; + let feeRecipient: AztecAddress; + // To overwrite the test data, set this to true and run the tests. const OVERWRITE_TEST_DATA = false; @@ -132,7 +136,7 @@ describe('L1Publisher integration', () => { publicClient, }); - builderDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); + builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); const vks = getVerificationKeys(); const simulator = new RealRollupCircuitSimulator(); const prover = new EmptyRollupProver(); @@ -149,6 +153,9 @@ describe('L1Publisher integration', () => { l1BlockPublishRetryIntervalMS: 100, }); + coinbase = config.coinbase || EthAddress.random(); + feeRecipient = config.feeRecipient || AztecAddress.random(); + prevHeader = await builderDb.buildInitialHeader(); }, 100_000); @@ -267,6 +274,8 @@ describe('L1Publisher integration', () => { chainId: Number(block.header.globalVariables.chainId.toBigInt()), timestamp: Number(block.header.globalVariables.timestamp.toBigInt()), version: Number(block.header.globalVariables.version.toBigInt()), + coinbase: `0x${block.header.globalVariables.coinbase.toBuffer().toString('hex').padStart(40, '0')}`, + feeRecipient: `0x${block.header.globalVariables.feeRecipient.toBuffer().toString('hex').padStart(64, '0')}`, }, lastArchive: { nextAvailableLeafIndex: block.header.lastArchive.nextAvailableLeafIndex, @@ -358,11 +367,14 @@ describe('L1Publisher integration', () => { await makeBloatedProcessedTx(totalNullifiersPerBlock * i + 3 * MAX_NEW_NULLIFIERS_PER_TX), await makeBloatedProcessedTx(totalNullifiersPerBlock * i + 4 * MAX_NEW_NULLIFIERS_PER_TX), ]; + const globalVariables = new GlobalVariables( new Fr(chainId), new Fr(config.version), new Fr(1 + i), new Fr(await rollup.read.lastBlockTs()), + coinbase, + feeRecipient, ); const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); prevHeader = block.header; @@ -440,11 +452,14 @@ describe('L1Publisher integration', () => { await makeEmptyProcessedTx(), await makeEmptyProcessedTx(), ]; + const globalVariables = new GlobalVariables( new Fr(chainId), new Fr(config.version), new Fr(1 + i), new Fr(await rollup.read.lastBlockTs()), + coinbase, + feeRecipient, ); const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); prevHeader = block.header; diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index 35d2d9480e2..766c4dcaa2a 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -75,6 +75,7 @@ "koa-router": "^12.0.0", "leveldown": "^6.1.1", "levelup": "^5.1.1", + "lodash.chunk": "^4.2.0", "lodash.clonedeepwith": "^4.5.0", "memdown": "^6.1.1", "pako": "^2.1.0", @@ -96,6 +97,7 @@ "@types/koa__cors": "^4.0.0", "@types/leveldown": "^4.0.3", "@types/levelup": "^5.1.2", + "@types/lodash.chunk": "^4.2.9", "@types/lodash.clonedeepwith": "^4.5.7", "@types/memdown": "^3.0.1", "@types/node": "^18.7.23", diff --git a/yarn-project/foundation/src/abi/abi_coder.ts b/yarn-project/foundation/src/abi/abi_coder.ts deleted file mode 100644 index a702e65153a..00000000000 --- a/yarn-project/foundation/src/abi/abi_coder.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { type ABIType } from './abi.js'; - -/** - * Get the size of an ABI type in field elements. - * @param type - The ABI type. - * @returns The size of the type in field elements. - */ -export function sizeOfType(type: ABIType): number { - switch (type.kind) { - case 'field': - case 'boolean': - case 'integer': - return 1; - case 'string': - return type.length; - case 'array': - return type.length * sizeOfType(type.type); - case 'struct': - return type.fields.reduce((sum, field) => sum + sizeOfType(field.type), 0); - default: { - const exhaustiveCheck: never = type; - throw new Error(`Unhandled abi type: ${exhaustiveCheck}`); - } - } -} diff --git a/yarn-project/foundation/src/abi/buffer.test.ts b/yarn-project/foundation/src/abi/buffer.test.ts new file mode 100644 index 00000000000..9c3329666c3 --- /dev/null +++ b/yarn-project/foundation/src/abi/buffer.test.ts @@ -0,0 +1,14 @@ +import { bufferAsFields, bufferFromFields } from './buffer.js'; + +describe('buffer', () => { + it('converts buffer back and forth from fields', () => { + const buffer = Buffer.from('1234567890abcdef'.repeat(10), 'hex'); + const fields = bufferAsFields(buffer, 20); + expect(bufferFromFields(fields).toString('hex')).toEqual(buffer.toString('hex')); + }); + + it('throws if max length is exceeded', () => { + const buffer = Buffer.from('1234567890abcdef'.repeat(10), 'hex'); + expect(() => bufferAsFields(buffer, 3)).toThrow(/exceeds maximum size/); + }); +}); diff --git a/yarn-project/foundation/src/abi/buffer.ts b/yarn-project/foundation/src/abi/buffer.ts new file mode 100644 index 00000000000..501f8070ea7 --- /dev/null +++ b/yarn-project/foundation/src/abi/buffer.ts @@ -0,0 +1,36 @@ +import chunk from 'lodash.chunk'; + +import { Fr } from '../fields/fields.js'; + +/** + * Formats a buffer as an array of fields. Splits the input into 31-byte chunks, and stores each + * of them into a field, omitting the field's first byte, then adds zero-fields at the end until the max length. + * @param input - Input to format. + * @param targetLength - Length of the target array in number of fields. + * @returns A field with the total length in bytes, followed by an array of fields such that their concatenation is equal to the input buffer, followed by enough zeroes to reach targetLength. + */ +export function bufferAsFields(input: Buffer, targetLength: number): Fr[] { + const encoded = [ + new Fr(input.length), + ...chunk(input, Fr.SIZE_IN_BYTES - 1).map(c => { + const fieldBytes = Buffer.alloc(Fr.SIZE_IN_BYTES); + Buffer.from(c).copy(fieldBytes, 1); + return Fr.fromBuffer(fieldBytes); + }), + ]; + if (encoded.length > targetLength) { + throw new Error(`Input buffer exceeds maximum size: got ${encoded.length} but max is ${targetLength}`); + } + // Fun fact: we cannot use padArrayEnd here since typescript cannot deal with a Tuple this big + return [...encoded, ...Array(targetLength - encoded.length).fill(Fr.ZERO)]; +} + +/** + * Recovers a buffer from an array of fields. + * @param fields - An output from bufferAsFields. + * @returns The recovered buffer. + */ +export function bufferFromFields(fields: Fr[]): Buffer { + const [length, ...payload] = fields; + return Buffer.concat(payload.map(f => f.toBuffer().subarray(1))).subarray(0, length.toNumber()); +} diff --git a/yarn-project/foundation/src/abi/index.ts b/yarn-project/foundation/src/abi/index.ts index 8369df9cd6e..3fd28c16cc4 100644 --- a/yarn-project/foundation/src/abi/index.ts +++ b/yarn-project/foundation/src/abi/index.ts @@ -1,5 +1,5 @@ export * from './abi.js'; -export * from './abi_coder.js'; +export * from './buffer.js'; export * from './encoder.js'; export * from './decoder.js'; export * from './selector.js'; diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index 760d3bd0931..b4e8911b70a 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -1,10 +1,9 @@ -import { fromHex, toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { BufferReader, FieldReader } from '@aztec/foundation/serialize'; - import { randomBytes } from 'crypto'; +import { fromHex, toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; import { keccak } from '../crypto/keccak/index.js'; import { Fr } from '../fields/index.js'; +import { BufferReader, FieldReader } from '../serialize/index.js'; import { type ABIParameter } from './abi.js'; import { decodeFunctionSignature } from './decoder.js'; @@ -154,7 +153,14 @@ export class FunctionSelector extends Selector { * @param parameters - An array of ABIParameter objects, each containing the type information of a function parameter. * @returns A Buffer containing the 4-byte selector. */ - static fromNameAndParameters(name: string, parameters: ABIParameter[]) { + static fromNameAndParameters(args: { name: string; parameters: ABIParameter[] }): FunctionSelector; + static fromNameAndParameters(name: string, parameters: ABIParameter[]): FunctionSelector; + static fromNameAndParameters( + nameOrArgs: string | { name: string; parameters: ABIParameter[] }, + maybeParameters?: ABIParameter[], + ): FunctionSelector { + const { name, parameters } = + typeof nameOrArgs === 'string' ? { name: nameOrArgs, parameters: maybeParameters! } : nameOrArgs; const signature = decodeFunctionSignature(name, parameters); const selector = this.fromSignature(signature); // If using the debug logger here it kill the typing in the `server_world_state_synchronizer` and jest tests. diff --git a/yarn-project/foundation/src/array/array.ts b/yarn-project/foundation/src/array/array.ts index a6a2e5b8bb1..274ad4bf36f 100644 --- a/yarn-project/foundation/src/array/array.ts +++ b/yarn-project/foundation/src/array/array.ts @@ -1,6 +1,6 @@ -import { Tuple } from '@aztec/foundation/serialize'; +import { Tuple } from '../serialize/index.js'; -export type { FieldsOf } from '@aztec/foundation/types'; +export type { FieldsOf } from '../types/index.js'; /** * Create an array over an integer range. diff --git a/yarn-project/foundation/src/eth-address/eth_address.test.ts b/yarn-project/foundation/src/eth-address/eth_address.test.ts index deff4f88e7c..2ae3e1bc736 100644 --- a/yarn-project/foundation/src/eth-address/eth_address.test.ts +++ b/yarn-project/foundation/src/eth-address/eth_address.test.ts @@ -8,7 +8,7 @@ describe('address', () => { it('should return correct buffer', () => { const address = EthAddress.fromString('0xc6d9d2cd449a754c494264e1809c50e34d64562b'); - expect(address.toBuffer20()).toEqual(Buffer.from('c6d9d2cD449A754c494264e1809c50e34D64562b', 'hex')); + expect(address.toBuffer()).toEqual(Buffer.from('c6d9d2cD449A754c494264e1809c50e34D64562b', 'hex')); }); it('should return correct 32 byte buffer', () => { @@ -18,16 +18,6 @@ describe('address', () => { ); }); - it('should create address from 32 byte buffer', () => { - const buffer = Buffer.from('000000000000000000000000c6d9d2cD449A754c494264e1809c50e34D64562b', 'hex'); - expect(new EthAddress(buffer)).toEqual(EthAddress.fromString('0xc6d9d2cD449A754c494264e1809c50e34D64562b')); - }); - - it('should not create address from 32 byte buffer that does not start with 12 0 bytes', () => { - const buffer = Buffer.from('010000000000000000000000c6d9d2cD449A754c494264e1809c50e34D64562b', 'hex'); - expect(() => new EthAddress(buffer)).toThrowError(); - }); - it('should have correct zero address', () => { expect(EthAddress.ZERO.toString()).toBe('0x0000000000000000000000000000000000000000'); }); diff --git a/yarn-project/foundation/src/eth-address/index.ts b/yarn-project/foundation/src/eth-address/index.ts index 7594a9ad345..592485c23b2 100644 --- a/yarn-project/foundation/src/eth-address/index.ts +++ b/yarn-project/foundation/src/eth-address/index.ts @@ -1,7 +1,7 @@ import { keccak256String } from '../crypto/keccak/index.js'; import { randomBytes } from '../crypto/random/index.js'; import { Fr } from '../fields/index.js'; -import { BufferReader } from '../serialize/index.js'; +import { BufferReader, FieldReader } from '../serialize/index.js'; /** * Represents an Ethereum address as a 20-byte buffer and provides various utility methods @@ -20,13 +20,7 @@ export class EthAddress { public static ZERO = new EthAddress(Buffer.alloc(EthAddress.SIZE_IN_BYTES)); constructor(private buffer: Buffer) { - if (buffer.length === 32) { - if (!buffer.slice(0, 12).equals(Buffer.alloc(12))) { - throw new Error(`Invalid address buffer: ${buffer.toString('hex')}`); - } else { - this.buffer = buffer.slice(12); - } - } else if (buffer.length !== EthAddress.SIZE_IN_BYTES) { + if (buffer.length !== EthAddress.SIZE_IN_BYTES) { throw new Error(`Expect buffer size to be ${EthAddress.SIZE_IN_BYTES}. Got ${buffer.length}.`); } } @@ -176,21 +170,10 @@ export class EthAddress { } /** - * Alias for toBuffer32. - * @returns A 32-byte Buffer containing the padded Ethereum address. + * Returns a 20-byte buffer representation of the Ethereum address. + * @returns A 20-byte Buffer containing the Ethereum address. */ public toBuffer() { - return this.toBuffer32(); - } - - /** - * Returns the internal Buffer representation of the Ethereum address. - * This method is useful when working with raw binary data or when - * integrating with other modules that require a Buffer as input. - * - * @returns A Buffer instance containing the 20-byte Ethereum address. - */ - public toBuffer20() { return this.buffer; } @@ -201,6 +184,7 @@ export class EthAddress { * * @returns A 32-byte Buffer containing the padded Ethereum address. */ + // TODO(#3938): nuke this public toBuffer32() { const buffer = Buffer.alloc(32); this.buffer.copy(buffer, 12); @@ -225,6 +209,11 @@ export class EthAddress { return new EthAddress(fr.toBuffer().slice(-EthAddress.SIZE_IN_BYTES)); } + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return EthAddress.fromField(reader.readField()); + } + /** * Deserializes from a buffer or reader, corresponding to a write in cpp. * @param buffer - Buffer to read from. @@ -232,7 +221,7 @@ export class EthAddress { */ static fromBuffer(buffer: Buffer | BufferReader): EthAddress { const reader = BufferReader.asReader(buffer); - return new EthAddress(reader.readBytes(32)); + return new EthAddress(reader.readBytes(EthAddress.SIZE_IN_BYTES)); } /** diff --git a/yarn-project/foundation/src/fields/fields.test.ts b/yarn-project/foundation/src/fields/fields.test.ts index 02f08f0e319..c2673ff86e9 100644 --- a/yarn-project/foundation/src/fields/fields.test.ts +++ b/yarn-project/foundation/src/fields/fields.test.ts @@ -1,4 +1,4 @@ -import { GrumpkinScalar } from './fields.js'; +import { Fr, GrumpkinScalar } from './fields.js'; describe('GrumpkinScalar Serialization', () => { // Test case for GrumpkinScalar.fromHighLow @@ -53,3 +53,122 @@ describe('GrumpkinScalar Serialization', () => { expect(deserialized).toEqual(original); }); }); + +describe('Bn254 arithmetic', () => { + describe('Addition', () => { + it('Low Boundary', () => { + // 0 + -1 = -1 + const a = Fr.ZERO; + const b = new Fr(Fr.MODULUS - 1n); + const expected = new Fr(Fr.MODULUS - 1n); + + const actual = a.add(b); + expect(actual).toEqual(expected); + }); + + it('High Boundary', () => { + // -1 + 1 = 0 + const a = new Fr(Fr.MODULUS - 1n); + const b = new Fr(1); + const expected = Fr.ZERO; + + const actual = a.add(b); + expect(actual).toEqual(expected); + }); + + it('Performs addition correctly', () => { + const a = new Fr(2); + const b = new Fr(3); + const expected = new Fr(5); + + const actual = a.add(b); + expect(actual).toEqual(expected); + }); + }); + + describe('Subtraction', () => { + it('Low Boundary', () => { + // 0 - 1 = -1 + const a = new Fr(0); + const b = new Fr(1); + const expected = new Fr(Fr.MODULUS - 1n); + + const actual = a.sub(b); + expect(actual).toEqual(expected); + }); + + it('High Bonudary', () => { + // -1 - (-1) = 0 + const a = new Fr(Fr.MODULUS - 1n); + const b = new Fr(Fr.MODULUS - 1n); + + const actual = a.sub(b); + expect(actual).toEqual(Fr.ZERO); + }); + + it('Performs subtraction correctly', () => { + const a = new Fr(10); + const b = new Fr(5); + const expected = new Fr(5); + + const actual = a.sub(b); + expect(actual).toEqual(expected); + }); + }); + + describe('Multiplication', () => { + it('Identity', () => { + const a = new Fr(Fr.MODULUS - 1n); + const b = new Fr(1); + const expected = new Fr(Fr.MODULUS - 1n); + + const actual = a.mul(b); + expect(actual).toEqual(expected); + }); + + it('Performs multiplication correctly', () => { + const a = new Fr(2); + const b = new Fr(3); + const expected = new Fr(6); + + const actual = a.mul(b); + expect(actual).toEqual(expected); + }); + + it('High Boundary', () => { + const a = new Fr(Fr.MODULUS - 1n); + const b = new Fr(Fr.MODULUS / 2n); + const expected = new Fr(10944121435919637611123202872628637544274182200208017171849102093287904247809n); + + const actual = a.mul(b); + expect(actual).toEqual(expected); + }); + }); + + describe('Division', () => { + it('Should succeed when mod inverse is -ve', () => { + const a = new Fr(2); + const b = new Fr(3); + + const actual = a.div(b); + expect(actual.mul(b)).toEqual(a); + }); + + it('Should succeed when mod inverse is +ve', () => { + const a = new Fr(10); + const b = new Fr(5); + const expected = new Fr(2); + + const actual = a.div(b); + expect(actual.mul(b)).toEqual(a); + expect(actual).toEqual(expected); + }); + + it('Should not allow a division by 0', () => { + const a = new Fr(10); + const b = Fr.ZERO; + + expect(() => a.div(b)).toThrowError(); + }); + }); +}); diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 0e622cd4fde..1f23f5473f5 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -51,7 +51,7 @@ abstract class BaseField { } else if (typeof value === 'bigint' || typeof value === 'number' || typeof value === 'boolean') { this.asBigInt = BigInt(value); if (this.asBigInt >= this.modulus()) { - throw new Error('Value >= to field modulus.'); + throw new Error(`Value 0x${this.asBigInt.toString(16)} is greater or equal to field modulus.`); } } else if (value instanceof BaseField) { this.asBuffer = value.asBuffer; @@ -89,12 +89,24 @@ abstract class BaseField { if (this.asBigInt === undefined) { this.asBigInt = toBigIntBE(this.asBuffer!); if (this.asBigInt >= this.modulus()) { - throw new Error('Value >= to field modulus.'); + throw new Error(`Value 0x${this.asBigInt.toString(16)} is greater or equal to field modulus.`); } } return this.asBigInt; } + toBool(): boolean { + return Boolean(this.toBigInt()); + } + + toNumber(): number { + const value = this.toBigInt(); + if (value > Number.MAX_SAFE_INTEGER) { + throw new Error(`Value ${value.toString(16)} greater than than max safe integer`); + } + return Number(value); + } + toShortString(): string { const str = this.toString(); return `${str.slice(0, 10)}...${str.slice(-4)}`; @@ -290,8 +302,8 @@ function modInverse(b: bigint) { if (gcd != 1n) { throw Error('Inverse does not exist'); } - // Add modulus to ensure positive - return new Fr(x + Fr.MODULUS); + // Add modulus if -ve to ensure positive + return new Fr(x > 0 ? x : x + Fr.MODULUS); } /** diff --git a/yarn-project/foundation/src/serialize/buffer_reader.ts b/yarn-project/foundation/src/serialize/buffer_reader.ts index d11efff3cb5..48c0c553c59 100644 --- a/yarn-project/foundation/src/serialize/buffer_reader.ts +++ b/yarn-project/foundation/src/serialize/buffer_reader.ts @@ -111,6 +111,13 @@ export class BufferReader { return Buffer.from(this.buffer.subarray(this.index - n, this.index)); } + /** Reads until the end of the buffer. */ + public readToEnd(): Buffer { + const result = this.buffer.subarray(this.index); + this.index = this.buffer.length; + return result; + } + /** * Reads a vector of numbers from the buffer and returns it as an array of numbers. * The method utilizes the 'readVector' method, passing a deserializer that reads numbers. diff --git a/yarn-project/foundation/src/serialize/free_funcs.ts b/yarn-project/foundation/src/serialize/free_funcs.ts index a9f9dcdfc1e..3ff2ea133a5 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.ts @@ -1,4 +1,4 @@ -import { Fr } from '@aztec/foundation/fields'; +import { Fr } from '../fields/fields.js'; /** * Convert a boolean value to its corresponding byte representation in a Buffer of size 1. diff --git a/yarn-project/foundation/src/serialize/serialize.ts b/yarn-project/foundation/src/serialize/serialize.ts index cf5ccc3f053..346fc7366e6 100644 --- a/yarn-project/foundation/src/serialize/serialize.ts +++ b/yarn-project/foundation/src/serialize/serialize.ts @@ -1,5 +1,4 @@ -import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; - +import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; import { Fr } from '../fields/fields.js'; import { numToUInt32BE } from './free_funcs.js'; @@ -105,12 +104,6 @@ export type Bufferable = | Buffer | number | string - | { - /** - * Serialize to a buffer of 32 bytes. - */ - toBuffer32: () => Buffer; - } | { /** * Serialize to a buffer. @@ -135,27 +128,6 @@ export type Fieldeable = } | Fieldeable[]; -/** - * Checks whether an object implements the toBuffer32 method. - * @param obj - The object to check. - * @returns Whether the object implements the toBuffer32 method. - */ -function isSerializableToBuffer32(obj: object): obj is { - /** - * Signature of the target serialization function. - */ - toBuffer32: () => Buffer; -} { - return !!( - obj as { - /** - * Signature of the target serialization function. - */ - toBuffer32: () => Buffer; - } - ).toBuffer32; -} - /** * Serializes a list of objects contiguously. * @param objs - Objects to serialize. @@ -176,8 +148,6 @@ export function serializeToBufferArray(...objs: Bufferable[]): Buffer[] { } else if (typeof obj === 'string') { ret.push(numToUInt32BE(obj.length)); ret.push(Buffer.from(obj)); - } else if (isSerializableToBuffer32(obj)) { - ret.push(obj.toBuffer32()); } else { ret.push(obj.toBuffer()); } diff --git a/yarn-project/foundation/src/serialize/types.ts b/yarn-project/foundation/src/serialize/types.ts index c6e90a4c542..af70fd793d0 100644 --- a/yarn-project/foundation/src/serialize/types.ts +++ b/yarn-project/foundation/src/serialize/types.ts @@ -16,7 +16,7 @@ type _Tuple = R['length'] extends N ? */ export function assertLength(array: T[], n: N): Tuple { if (array.length !== n) { - throw new Error("Wrong 'fixed array' size"); + throw new Error(`Wrong 'fixed array' size. Expected ${n}, got ${array.length}.`); } return array as Tuple; } diff --git a/yarn-project/foundation/src/types/index.ts b/yarn-project/foundation/src/types/index.ts index 80c6fcbfe5a..ff34c215611 100644 --- a/yarn-project/foundation/src/types/index.ts +++ b/yarn-project/foundation/src/types/index.ts @@ -1,7 +1,8 @@ -/** - * Strips methods of a type. - */ +/** Strips methods of a type. */ export type FieldsOf = { // eslint-disable-next-line @typescript-eslint/ban-types [P in keyof T as T[P] extends Function ? never : P]: T[P]; }; + +/** Marks a set of properties of a type as optional. */ +export type PartialBy = Omit & Partial>; diff --git a/yarn-project/kv-store/package.json b/yarn-project/kv-store/package.json index 4c440901969..55808c67312 100644 --- a/yarn-project/kv-store/package.json +++ b/yarn-project/kv-store/package.json @@ -2,7 +2,11 @@ "name": "@aztec/kv-store", "version": "0.1.0", "type": "module", - "exports": "./dest/index.js", + "exports": { + ".": "./dest/interfaces/index.js", + "./lmdb": "./dest/lmdb/index.js", + "./utils": "./dest/utils.js" + }, "scripts": { "build": "yarn clean && tsc -b", "build:dev": "tsc -b --watch", @@ -43,7 +47,6 @@ "src", "!*.test.*" ], - "types": "./dest/index.d.ts", "engines": { "node": ">=18" } diff --git a/yarn-project/kv-store/src/index.ts b/yarn-project/kv-store/src/index.ts deleted file mode 100644 index b35a4fb3d53..00000000000 --- a/yarn-project/kv-store/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export * from './interfaces/array.js'; -export * from './interfaces/map.js'; -export * from './interfaces/counter.js'; -export * from './interfaces/singleton.js'; -export * from './interfaces/store.js'; -export * from './lmdb/store.js'; -export { Range } from './interfaces/common.js'; diff --git a/yarn-project/kv-store/src/interfaces/index.ts b/yarn-project/kv-store/src/interfaces/index.ts new file mode 100644 index 00000000000..e478b630e65 --- /dev/null +++ b/yarn-project/kv-store/src/interfaces/index.ts @@ -0,0 +1,6 @@ +export * from './array.js'; +export * from './map.js'; +export * from './counter.js'; +export * from './singleton.js'; +export * from './store.js'; +export { Range } from './common.js'; diff --git a/yarn-project/kv-store/src/interfaces/store.ts b/yarn-project/kv-store/src/interfaces/store.ts index 2e2777f0e8a..9b0f1c9364d 100644 --- a/yarn-project/kv-store/src/interfaces/store.ts +++ b/yarn-project/kv-store/src/interfaces/store.ts @@ -45,4 +45,9 @@ export interface AztecKVStore { * @param callback - The callback to execute in a transaction */ transaction>>(callback: () => T): Promise; + + /** + * Clears the store + */ + clear(): Promise; } diff --git a/yarn-project/kv-store/src/lmdb/index.ts b/yarn-project/kv-store/src/lmdb/index.ts new file mode 100644 index 00000000000..53e012fa539 --- /dev/null +++ b/yarn-project/kv-store/src/lmdb/index.ts @@ -0,0 +1 @@ +export { AztecLmdbStore } from './store.js'; diff --git a/yarn-project/kv-store/src/lmdb/store.ts b/yarn-project/kv-store/src/lmdb/store.ts index bbd866efe8c..7f9286403ce 100644 --- a/yarn-project/kv-store/src/lmdb/store.ts +++ b/yarn-project/kv-store/src/lmdb/store.ts @@ -1,5 +1,4 @@ -import { EthAddress } from '@aztec/foundation/eth-address'; -import { Logger, createDebugLogger } from '@aztec/foundation/log'; +import { createDebugLogger } from '@aztec/foundation/log'; import { Database, Key, RootDatabase, open } from 'lmdb'; @@ -20,12 +19,9 @@ export class AztecLmdbStore implements AztecKVStore { #rootDb: RootDatabase; #data: Database; #multiMapData: Database; - #rollupAddress: AztecSingleton; - #log: Logger; - constructor(rootDb: RootDatabase, log: Logger) { + constructor(rootDb: RootDatabase) { this.#rootDb = rootDb; - this.#log = log; // big bucket to store all the data this.#data = rootDb.openDB('data', { @@ -38,8 +34,6 @@ export class AztecLmdbStore implements AztecKVStore { keyEncoding: 'ordered-binary', dupSort: true, }); - - this.#rollupAddress = this.openSingleton('rollupAddress'); } /** @@ -50,30 +44,14 @@ export class AztecLmdbStore implements AztecKVStore { * the database is cleared before returning the store. This way data is not accidentally shared between * different rollup instances. * - * @param rollupAddress - The ETH address of the rollup contract * @param path - A path on the disk to store the database. Optional * @param log - A logger to use. Optional * @returns The store */ - static async open( - rollupAddress: EthAddress, - path?: string, - log = createDebugLogger('aztec:kv-store:lmdb'), - ): Promise { + static open(path?: string, log = createDebugLogger('aztec:kv-store:lmdb')): AztecLmdbStore { log.info(`Opening LMDB database at ${path || 'temporary location'}`); - - const rootDb = open({ - path, - }); - - const db = new AztecLmdbStore(rootDb, log); - await db.#init(rollupAddress); - - return db; - } - - static openTmp(): Promise { - return AztecLmdbStore.open(EthAddress.random()); + const rootDb = open({ path }); + return new AztecLmdbStore(rootDb); } /** @@ -125,17 +103,10 @@ export class AztecLmdbStore implements AztecKVStore { return this.#rootDb.transaction(callback); } - async #init(rollupAddress: EthAddress): Promise { - const storedRollupAddress = this.#rollupAddress.get(); - const rollupAddressString = rollupAddress.toString(); - - if (typeof storedRollupAddress === 'string' && rollupAddressString !== storedRollupAddress) { - this.#log.warn( - `Rollup address mismatch: expected ${rollupAddress}, found ${storedRollupAddress}. Clearing entire database...`, - ); - await this.#rootDb.clearAsync(); - } - - await this.#rollupAddress.set(rollupAddressString); + /** + * Clears the store + */ + async clear() { + await this.#rootDb.clearAsync(); } } diff --git a/yarn-project/kv-store/src/utils.ts b/yarn-project/kv-store/src/utils.ts new file mode 100644 index 00000000000..7cab23f5827 --- /dev/null +++ b/yarn-project/kv-store/src/utils.ts @@ -0,0 +1,41 @@ +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Logger } from '@aztec/foundation/log'; + +import { AztecKVStore } from './interfaces/store.js'; +import { AztecLmdbStore } from './lmdb/store.js'; + +/** + * Clears the store if the rollup address does not match the one stored in the database. + * This is to prevent data from being accidentally shared between different rollup instances. + * @param store - The store to check + * @param rollupAddress - The ETH address of the rollup contract + * @returns A promise that resolves when the store is cleared, or rejects if the rollup address does not match + */ +export async function initStoreForRollup( + store: T, + rollupAddress: EthAddress, + log?: Logger, +): Promise { + const rollupAddressValue = store.openSingleton>('rollupAddress'); + const rollupAddressString = rollupAddress.toString(); + const storedRollupAddressString = rollupAddressValue.get(); + + if (typeof storedRollupAddressString !== 'undefined' && storedRollupAddressString !== rollupAddressString) { + log?.warn( + `Rollup address mismatch: expected ${rollupAddress}, found ${rollupAddressValue}. Clearing entire database...`, + ); + + await store.clear(); + } + + await rollupAddressValue.set(rollupAddressString); + return store; +} + +/** + * Opens a temporary store for testing purposes. + * @returns A new store + */ +export function openTmpStore(): AztecKVStore { + return AztecLmdbStore.open(); +} diff --git a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts index 52ebdec437d..f1b2d458b72 100644 --- a/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/append_only_snapshot.test.ts @@ -1,4 +1,5 @@ -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Pedersen, StandardTree, newTree } from '../index.js'; import { AppendOnlySnapshotBuilder } from './append_only_snapshot.js'; @@ -10,7 +11,7 @@ describe('AppendOnlySnapshot', () => { let db: AztecKVStore; beforeEach(async () => { - db = await AztecLmdbStore.openTmp(); + db = openTmpStore(); const hasher = new Pedersen(); tree = await newTree(StandardTree, db, hasher, 'test', 4); snapshotBuilder = new AppendOnlySnapshotBuilder(db, tree, hasher); diff --git a/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts index 4219dbd1c45..6e57e113f93 100644 --- a/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/full_snapshot.test.ts @@ -1,4 +1,5 @@ -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Pedersen, StandardTree, newTree } from '../index.js'; import { FullTreeSnapshotBuilder } from './full_snapshot.js'; @@ -10,7 +11,7 @@ describe('FullSnapshotBuilder', () => { let db: AztecKVStore; beforeEach(async () => { - db = await AztecLmdbStore.openTmp(); + db = openTmpStore(); tree = await newTree(StandardTree, db, new Pedersen(), 'test', 4); snapshotBuilder = new FullTreeSnapshotBuilder(db, tree); }); diff --git a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts index e1ba0b9e0f7..81f5ccb5b20 100644 --- a/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts +++ b/yarn-project/merkle-tree/src/snapshots/indexed_tree_snapshot.test.ts @@ -1,5 +1,6 @@ import { Fr, NullifierLeaf, NullifierLeafPreimage } from '@aztec/circuits.js'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { Pedersen, newTree } from '../index.js'; @@ -19,7 +20,7 @@ describe('IndexedTreeSnapshotBuilder', () => { let snapshotBuilder: IndexedTreeSnapshotBuilder; beforeEach(async () => { - db = await AztecLmdbStore.openTmp(); + db = openTmpStore(); tree = await newTree(NullifierTree, db, new Pedersen(), 'test', 4); snapshotBuilder = new IndexedTreeSnapshotBuilder(db, tree, NullifierLeafPreimage); }); diff --git a/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.test.ts b/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.test.ts index 21ce5c2b767..05b869932e6 100644 --- a/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.test.ts +++ b/yarn-project/merkle-tree/src/sparse_tree/sparse_tree.test.ts @@ -1,6 +1,7 @@ import { SiblingPath } from '@aztec/circuit-types'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { randomBytes } from 'crypto'; @@ -36,7 +37,7 @@ describe('SparseTreeSpecific', () => { }); it('throws when index is bigger than (2^DEPTH - 1) ', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const depth = 32; const tree = await createDb(db, pedersen, 'test', depth); @@ -48,7 +49,7 @@ describe('SparseTreeSpecific', () => { const depth = 32; const maxIndex = 2 ** depth - 1; - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', depth); const randomIndex = BigInt(Math.floor(Math.random() * maxIndex)); @@ -67,7 +68,7 @@ describe('SparseTreeSpecific', () => { const depth = 254; const maxIndex = 2 ** depth - 1; - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', depth); const randomIndex = BigInt(Math.floor(Math.random() * maxIndex)); @@ -83,7 +84,7 @@ describe('SparseTreeSpecific', () => { }); it('should have correct root and sibling path after in a "non-append-only" way', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 3); const level2ZeroHash = pedersen.hash(INITIAL_LEAF, INITIAL_LEAF); @@ -156,7 +157,7 @@ describe('SparseTreeSpecific', () => { const depth = 254; const maxIndex = 2 ** depth - 1; - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', depth); const leaves = Array.from({ length: 1000 }).map(() => randomBytes(32)); diff --git a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts index 6543283df8c..7454aad786f 100644 --- a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts +++ b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree.test.ts @@ -7,7 +7,8 @@ import { PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { INITIAL_LEAF, MerkleTree, Pedersen, loadTree, newTree } from '../../index.js'; @@ -75,7 +76,7 @@ describe('StandardIndexedTreeSpecific', () => { it('produces the correct roots and sibling paths', async () => { // Create a depth-3 indexed merkle tree - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 3); /** @@ -272,7 +273,7 @@ describe('StandardIndexedTreeSpecific', () => { it('Can append empty leaves and handle insertions', async () => { // Create a depth-3 indexed merkle tree - const tree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', 3); + const tree = await createDb(openTmpStore(), pedersen, 'test', 3); /** * Initial state: @@ -489,8 +490,8 @@ describe('StandardIndexedTreeSpecific', () => { const SUBTREE_HEIGHT = 5; // originally from BaseRollupInputs.NULLIFIER_SUBTREE_HEIGHT // Create a depth-3 indexed merkle tree - const appendTree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); - const insertTree = await createDb(await AztecLmdbStore.openTmp(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); + const appendTree = await createDb(openTmpStore(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); + const insertTree = await createDb(openTmpStore(), pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); await appendTree.appendLeaves(leaves); await insertTree.batchInsert(leaves, SUBTREE_HEIGHT); @@ -501,7 +502,7 @@ describe('StandardIndexedTreeSpecific', () => { }); it('should be able to find indexes of leaves', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 3); const values = [Buffer.alloc(32, 1), Buffer.alloc(32, 2)]; @@ -519,7 +520,7 @@ describe('StandardIndexedTreeSpecific', () => { describe('Updatable leaves', () => { it('should be able to upsert leaves', async () => { // Create a depth-3 indexed merkle tree - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await newTree(PublicDataTree, db, pedersen, 'test', 3, 1); /** @@ -629,7 +630,7 @@ describe('StandardIndexedTreeSpecific', () => { const INITIAL_TREE_SIZE = 8; const SUBTREE_HEIGHT = 5; - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const appendTree = await newTree(PublicDataTree, db, pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); const insertTree = await newTree(PublicDataTree, db, pedersen, 'test', TREE_HEIGHT, INITIAL_TREE_SIZE); diff --git a/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts index 7da886753aa..465f5a59a64 100644 --- a/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts +++ b/yarn-project/merkle-tree/src/standard_tree/standard_tree.test.ts @@ -1,5 +1,6 @@ import { randomBytes } from '@aztec/foundation/crypto'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { loadTree } from '../load_tree.js'; @@ -33,7 +34,7 @@ describe('StandardTree_batchAppend', () => { }); it('correctly computes root when batch appending and calls hash function expected num times', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 3); const leaves = Array.from({ length: 5 }, _ => randomBytes(32)); @@ -69,7 +70,7 @@ describe('StandardTree_batchAppend', () => { }); it('should be able to find indexes of leaves', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 3); const values = [Buffer.alloc(32, 1), Buffer.alloc(32, 2)]; diff --git a/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts b/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts index f970a9c89aa..9931e074131 100644 --- a/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts +++ b/yarn-project/merkle-tree/src/test/standard_based_test_suite.ts @@ -1,5 +1,6 @@ import { SiblingPath } from '@aztec/circuit-types'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { randomBytes } from 'crypto'; @@ -35,21 +36,21 @@ export const standardBasedTreeTestSuite = ( }); it('should have correct empty tree root for depth 32', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 32); const root = tree.getRoot(false); expect(root.toString('hex')).toEqual('16642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb'); }); it('should throw when appending beyond max index', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 2); const leaves = Array.from({ length: 5 }, _ => randomBytes(32)); await expect(appendLeaves(tree, leaves)).rejects.toThrow(); }); it('should have correct root and sibling paths', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 2); const level1ZeroHash = pedersen.hash(INITIAL_LEAF, INITIAL_LEAF); diff --git a/yarn-project/merkle-tree/src/test/test_suite.ts b/yarn-project/merkle-tree/src/test/test_suite.ts index c7fdd51b103..74b75c5dd43 100644 --- a/yarn-project/merkle-tree/src/test/test_suite.ts +++ b/yarn-project/merkle-tree/src/test/test_suite.ts @@ -1,5 +1,6 @@ import { SiblingPath } from '@aztec/circuit-types'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Hasher } from '@aztec/types/interfaces'; import { Pedersen } from '../index.js'; @@ -50,10 +51,10 @@ export const treeTestSuite = ( }); it('should revert changes on rollback', async () => { - const dbEmpty = await AztecLmdbStore.openTmp(); + const dbEmpty = openTmpStore(); const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test2', 10); await appendLeaves(tree, values.slice(0, 4)); @@ -85,10 +86,10 @@ export const treeTestSuite = ( }); it('should not revert changes after commit', async () => { - const dbEmpty = await AztecLmdbStore.openTmp(); + const dbEmpty = openTmpStore(); const emptyTree = await createDb(dbEmpty, pedersen, 'test', 10); - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test2', 10); await appendLeaves(tree, values.slice(0, 4)); @@ -104,7 +105,7 @@ export const treeTestSuite = ( }); it('should be able to restore from previous committed data', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 10); await appendLeaves(tree, values.slice(0, 4)); await tree.commit(); @@ -121,7 +122,7 @@ export const treeTestSuite = ( }); it('should throw an error if previous data does not exist for the given name', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); await expect( (async () => { await createFromName(db, pedersen, 'a_whole_new_tree'); @@ -130,7 +131,7 @@ export const treeTestSuite = ( }); it('should serialize sibling path data to a buffer and be able to deserialize it back', async () => { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const tree = await createDb(db, pedersen, 'test', 10); await appendLeaves(tree, values.slice(0, 1)); diff --git a/yarn-project/noir-contracts/Nargo.toml b/yarn-project/noir-contracts/Nargo.toml index 4c919e77911..d55caac75d5 100644 --- a/yarn-project/noir-contracts/Nargo.toml +++ b/yarn-project/noir-contracts/Nargo.toml @@ -4,6 +4,8 @@ members = [ "contracts/benchmarking_contract", "contracts/card_game_contract", "contracts/child_contract", + "contracts/contract_class_registerer_contract", + "contracts/contract_instance_deployer_contract", "contracts/counter_contract", "contracts/docs_example_contract", "contracts/easy_private_token_contract", diff --git a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr index 28dbf5576d0..405432acb7c 100644 --- a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -2,10 +2,14 @@ contract AvmTest { // Libs - use dep::aztec::protocol_types::{ - address::AztecAddress, + use dep::aztec::protocol_types::address::{ + AztecAddress, + EthAddress, }; + // avm lib + use dep::aztec::avm::context::AvmContext; + #[aztec(private)] fn constructor() {} @@ -15,6 +19,74 @@ contract AvmTest { argA + argB } + /************************************************************************ + * AvmContext functions + ************************************************************************/ + #[aztec(public-vm)] + fn getAddress() -> pub AztecAddress { + context.address() + } + + #[aztec(public-vm)] + fn getStorageAddress() -> pub AztecAddress { + context.storage_address() + } + + #[aztec(public-vm)] + fn getSender() -> pub AztecAddress { + context.sender() + } + + #[aztec(public-vm)] + fn getOrigin() -> pub AztecAddress { + context.origin() + } + + #[aztec(public-vm)] + fn getPortal() -> pub EthAddress { + context.portal() + } + + #[aztec(public-vm)] + fn getFeePerL1Gas() -> pub Field { + context.fee_per_l1_gas() + } + + #[aztec(public-vm)] + fn getFeePerL2Gas() -> pub Field { + context.fee_per_l2_gas() + } + + #[aztec(public-vm)] + fn getFeePerDaGas() -> pub Field { + context.fee_per_da_gas() + } + + #[aztec(public-vm)] + fn getChainId() -> pub Field { + context.chain_id() + } + + #[aztec(public-vm)] + fn getVersion() -> pub Field { + context.version() + } + + #[aztec(public-vm)] + fn getBlockNumber() -> pub Field { + context.block_number() + } + + #[aztec(public-vm)] + fn getTimestamp() -> pub Field { + context.timestamp() + } + + // #[aztec(public-vm)] + // fn getContractCallDepth() -> pub Field { + // context.contract_call_depth() + // } + // Function required for all contracts unconstrained fn compute_note_hash_and_nullifier( _contract_address: AztecAddress, diff --git a/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr b/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr index 46461faf1fb..0b4424ac9b5 100644 --- a/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/card_game_contract/src/main.nr @@ -25,15 +25,9 @@ contract CardGame { }, }; - use dep::aztec::{ - abi, - abi::{ - Hasher, PrivateContextInputs, - }, - note::{ - note_header::NoteHeader, - utils as note_utils, - }, + use dep::aztec::note::{ + note_header::NoteHeader, + utils as note_utils, }; use crate::cards::{ diff --git a/yarn-project/noir-contracts/contracts/child_contract/src/main.nr b/yarn-project/noir-contracts/contracts/child_contract/src/main.nr index 1298819f326..a830f36be2b 100644 --- a/yarn-project/noir-contracts/contracts/child_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/child_contract/src/main.nr @@ -3,13 +3,15 @@ contract Child { use dep::std::option::Option; use dep::aztec::{ - abi::CallContext, context::{PrivateContext, PublicContext, Context}, log::emit_unencrypted_log, state_vars::public_state::PublicState, }; use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, + abis::{ + call_context::CallContext, + function_selector::FunctionSelector, + }, address::AztecAddress, }; diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml new file mode 100644 index 00000000000..f500e459537 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "contract_class_registerer_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events.nr new file mode 100644 index 00000000000..b453b9acda4 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events.nr @@ -0,0 +1,3 @@ +mod class_registered; +mod private_function_broadcasted; +mod unconstrained_function_broadcasted; diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr new file mode 100644 index 00000000000..7fc4812ab61 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/class_registered.nr @@ -0,0 +1,29 @@ +use dep::aztec::protocol_types::{ + contract_class::ContractClassId, + constants::{MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}, + traits::{Serialize} +}; + +// #[event] +struct ContractClassRegistered { + contract_class_id: ContractClassId, + version: Field, + artifact_hash: Field, + private_functions_root: Field, + packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS], +} + +impl Serialize for ContractClassRegistered { + fn serialize(self: Self) -> [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5] { + let mut packed = [0; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS + 5]; + packed[0] = REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE; + packed[1] = self.contract_class_id.to_field(); + packed[2] = self.version; + packed[3] = self.artifact_hash; + packed[4] = self.private_functions_root; + for i in 0..MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS { + packed[i + 5] = self.packed_public_bytecode[i]; + } + packed + } +} diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr new file mode 100644 index 00000000000..6f1b9c07117 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr @@ -0,0 +1,58 @@ +use dep::aztec::protocol_types; +use dep::aztec::protocol_types::{ + contract_class::ContractClassId, + abis::function_selector::FunctionSelector, + constants::{FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE}, + traits::{Serialize} +}; + +struct PrivateFunction { + selector: FunctionSelector, + metadata_hash: Field, + vk_hash: Field, + bytecode: [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS], +} + +impl Serialize for PrivateFunction { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 3] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 3]; + packed[0] = self.selector.to_field(); + packed[1] = self.metadata_hash; + packed[2] = self.vk_hash; + for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS { + packed[i + 3] = self.bytecode[i]; + } + packed + } +} + +// #[event] +struct ClassPrivateFunctionBroadcasted { + contract_class_id: ContractClassId, + artifact_metadata_hash: Field, + unconstrained_functions_artifact_tree_root: Field, + private_function_tree_sibling_path: [Field; FUNCTION_TREE_HEIGHT], + artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + function: PrivateFunction +} + +impl Serialize for ClassPrivateFunctionBroadcasted { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17]; + packed[0] = REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE; + packed[1] = self.contract_class_id.to_field(); + packed[2] = self.artifact_metadata_hash; + packed[3] = self.unconstrained_functions_artifact_tree_root; + for i in 0..FUNCTION_TREE_HEIGHT { + packed[i + 4] = self.private_function_tree_sibling_path[i]; + } + for i in 0..ARTIFACT_FUNCTION_TREE_MAX_HEIGHT { + packed[i + 4 + FUNCTION_TREE_HEIGHT] = self.private_function_tree_sibling_path[i]; + } + let packed_function = self.function.serialize(); + for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 3 { + packed[i + 4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = packed_function[i]; + } + packed + } +} diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr new file mode 100644 index 00000000000..6ee5bb3bc26 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr @@ -0,0 +1,52 @@ +use dep::aztec::protocol_types; +use dep::aztec::protocol_types::{ + contract_class::ContractClassId, + abis::function_selector::FunctionSelector, + constants::{ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE}, + traits::{Serialize} +}; + +struct UnconstrainedFunction { + selector: FunctionSelector, + metadata_hash: Field, + bytecode: [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS], +} + +impl Serialize for UnconstrainedFunction { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 2] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 2]; + packed[0] = self.selector.to_field(); + packed[1] = self.metadata_hash; + for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS { + packed[i + 2] = self.bytecode[i]; + } + packed + } +} + +// #[event] +struct ClassUnconstrainedFunctionBroadcasted { + contract_class_id: ContractClassId, + artifact_metadata_hash: Field, + private_functions_artifact_tree_root: Field, + artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + function: UnconstrainedFunction +} + +impl Serialize for ClassUnconstrainedFunctionBroadcasted { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11]; + packed[0] = REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE; + packed[1] = self.contract_class_id.to_field(); + packed[2] = self.artifact_metadata_hash; + packed[3] = self.private_functions_artifact_tree_root; + for i in 0..ARTIFACT_FUNCTION_TREE_MAX_HEIGHT { + packed[i + 4] = self.artifact_function_tree_sibling_path[i]; + } + let packed_function = self.function.serialize(); + for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 2 { + packed[i + 4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT] = packed_function[i]; + } + packed + } +} diff --git a/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr new file mode 100644 index 00000000000..050a5a5ccd9 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -0,0 +1,91 @@ +mod events; + +contract ContractClassRegisterer { + use dep::std::option::Option; + use dep::aztec::protocol_types::{ + address::{ AztecAddress, EthAddress }, + contract_class::ContractClassId, + constants::{ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, FUNCTION_TREE_HEIGHT, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}, + traits::{Serialize} + }; + + use dep::aztec::log::{ emit_unencrypted_log, emit_unencrypted_log_from_private}; + + use crate::events::{ + class_registered::ContractClassRegistered, + private_function_broadcasted::{ClassPrivateFunctionBroadcasted, PrivateFunction}, + unconstrained_function_broadcasted::{ClassUnconstrainedFunctionBroadcasted, UnconstrainedFunction} + }; + + #[aztec(private)] + fn constructor() {} + + #[aztec(private)] + fn register( + artifact_hash: Field, + private_functions_root: Field, + public_bytecode_commitment: Field, + packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS] + ) { + // TODO: Validate public_bytecode_commitment is the correct commitment of packed_public_bytecode + // TODO: Validate packed_public_bytecode is legit public bytecode + + // Compute contract class id from preimage + let contract_class_id = ContractClassId::compute( + artifact_hash, + private_functions_root, + public_bytecode_commitment + ); + + // Emit the contract class id as a nullifier to be able to prove that this class has been (not) registered + let event = ContractClassRegistered { contract_class_id, version: 1, artifact_hash, private_functions_root, packed_public_bytecode }; + context.push_new_nullifier(contract_class_id.to_field(), 0); + + // Broadcast class info including public bytecode + let event_payload = event.serialize(); + dep::aztec::oracle::debug_log::debug_log_array_with_prefix("ContractClassRegistered", event_payload); + emit_unencrypted_log_from_private(&mut context, event_payload); + } + + #[aztec(private)] + fn broadcast_private_function( + contract_class_id: ContractClassId, + artifact_metadata_hash: Field, + unconstrained_functions_artifact_tree_root: Field, + private_function_tree_sibling_path: [Field; FUNCTION_TREE_HEIGHT], + artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + function_data: PrivateFunction + ) { + let event = ClassPrivateFunctionBroadcasted { + contract_class_id, + artifact_metadata_hash, + unconstrained_functions_artifact_tree_root, + private_function_tree_sibling_path, + artifact_function_tree_sibling_path, + function: function_data + }; + let event_payload = event.serialize(); + dep::aztec::oracle::debug_log::debug_log_array_with_prefix("ClassPrivateFunctionBroadcasted", event_payload); + emit_unencrypted_log_from_private(&mut context, event_payload); + } + + #[aztec(private)] + fn broadcast_unconstrained_function( + contract_class_id: ContractClassId, + artifact_metadata_hash: Field, + private_functions_artifact_tree_root: Field, + artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + function_data: UnconstrainedFunction + ) { + let event = ClassUnconstrainedFunctionBroadcasted { + contract_class_id, + artifact_metadata_hash, + private_functions_artifact_tree_root, + artifact_function_tree_sibling_path, + function: function_data + }; + let event_payload = event.serialize(); + dep::aztec::oracle::debug_log::debug_log_array_with_prefix("ClassUnconstrainedFunctionBroadcasted", event_payload); + emit_unencrypted_log_from_private(&mut context, event_payload); + } +} diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml new file mode 100644 index 00000000000..aeca13c16a4 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "contract_instance_deployer_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events.nr b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events.nr new file mode 100644 index 00000000000..d2b6ed6033f --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events.nr @@ -0,0 +1 @@ +mod instance_deployed; diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr new file mode 100644 index 00000000000..932973d45b1 --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr @@ -0,0 +1,36 @@ +use dep::aztec::protocol_types::{ + contract_class::ContractClassId, + address::{ AztecAddress, EthAddress, PublicKeysHash, PartialAddress }, + constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, + traits::{Serialize} +}; + +// #[event] +struct ContractInstanceDeployed { + address: AztecAddress, + version: u8, + salt: Field, + contract_class_id: ContractClassId, + initialization_hash: Field, + portal_contract_address: EthAddress, + public_keys_hash: PublicKeysHash, + universal_deploy: bool, +} + +global CONTRACT_INSTANCE_DEPLOYED_SERIALIZED_SIZE: Field = 9; + +impl Serialize for ContractInstanceDeployed { + fn serialize(self: Self) -> [Field; CONTRACT_INSTANCE_DEPLOYED_SERIALIZED_SIZE] { + [ + DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE, + self.address.to_field(), + self.version as Field, + self.salt, + self.contract_class_id.to_field(), + self.initialization_hash, + self.portal_contract_address.to_field(), + self.public_keys_hash.to_field(), + self.universal_deploy as Field, + ] + } +} diff --git a/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr new file mode 100644 index 00000000000..679085f994c --- /dev/null +++ b/yarn-project/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -0,0 +1,63 @@ +mod events; + +contract ContractInstanceDeployer { + use dep::std::option::Option; + use dep::aztec::protocol_types::{ + address::{ AztecAddress, EthAddress, PublicKeysHash, PartialAddress }, + contract_class::ContractClassId, + constants::{DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE}, + traits::{Serialize} + }; + + use dep::aztec::log::{ emit_unencrypted_log, emit_unencrypted_log_from_private}; + + use crate::events::{ + instance_deployed::ContractInstanceDeployed, + }; + + #[aztec(private)] + fn constructor() {} + + #[aztec(private)] + fn deploy( + salt: Field, + contract_class_id: ContractClassId, + initialization_hash: Field, + portal_contract_address: EthAddress, + public_keys_hash: PublicKeysHash, + universal_deploy: bool + ) { + // TODO(@spalladino): assert nullifier_exists silo(contract_class_id, ContractClassRegisterer) + // TODO(@spalladino): assert is_valid_eth_address(portal_contract_address) + + // TODO(#4434) Add deployer field to instance calculation + // let deployer = if universal_deploy { Field::zero() } else { context.msg_sender() }; + + let partial_address = PartialAddress::compute( + contract_class_id, + salt, + initialization_hash, + portal_contract_address + ); + + let address = AztecAddress::compute(public_keys_hash, partial_address); + + // Emit the address as a nullifier to be able to prove that this instance has been (not) deployed + context.push_new_nullifier(address.to_field(), 0); + + // Broadcast the event + let event = ContractInstanceDeployed { + contract_class_id, + address, + public_keys_hash, + portal_contract_address, + initialization_hash, + salt, + universal_deploy, + version: 1 + }; + let event_payload = event.serialize(); + dep::aztec::oracle::debug_log::debug_log_array_with_prefix("ContractInstanceDeployed", event_payload); + emit_unencrypted_log_from_private(&mut context, event_payload); + } +} diff --git a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr index 7182013b426..d884a56a40f 100644 --- a/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -244,10 +244,10 @@ contract DocsExample { } /// Macro equivalence section - use dep::aztec::abi; - use dep::aztec::abi::Hasher; - use dep::aztec::abi::PrivateContextInputs; - use dep::aztec::abi::PrivateCircuitPublicInputs; + use dep::aztec::hasher::Hasher; + + use dep::aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs; + use dep::aztec::context::inputs::PrivateContextInputs; // docs:start:simple_macro_example #[aztec(private)] @@ -270,7 +270,7 @@ contract DocsExample { b: Field // The actual return type of our circuit is the PrivateCircuitPublicInputs struct, this will be the // input to our kernel! // docs:start:context-example-return - ) -> distinct pub abi::PrivateCircuitPublicInputs { + ) -> distinct pub PrivateCircuitPublicInputs { // docs:end:context-example-return // ************************************************************ // The hasher is a structure used to generate a hash of the circuits inputs. diff --git a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index d343f255f0a..b94b576b364 100644 --- a/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -3,11 +3,13 @@ mod ecdsa_public_key_note; // Account contract that uses ECDSA signatures for authentication on the same curve as Ethereum. // The signing key is stored in an immutable private note and should be different from the signing key. contract EcdsaAccount { - use dep::aztec::protocol_types::address::AztecAddress; + use dep::aztec::protocol_types::{ + abis::call_context::CallContext, + address::AztecAddress, + }; use dep::std; use dep::std::option::Option; use dep::aztec::{ - abi::CallContext, context::{PrivateContext, PublicContext, Context}, note::{ note_header::NoteHeader, diff --git a/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr index 82ac8a1bd2e..613d3549b4c 100644 --- a/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/import_test_contract/src/main.nr @@ -19,7 +19,7 @@ contract ImportTest { // Calls the testCodeGen on the Test contract at the target address // Used for testing calling a function with arguments of multiple types - // See yarn-project/acir-simulator/src/client/private_execution.ts + // See yarn-project/simulator/src/client/private_execution.ts // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] fn main(target: AztecAddress) -> Field { diff --git a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index c3adf017e34..1e0a2917cb1 100644 --- a/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -18,6 +18,7 @@ contract InclusionProofs { context::Context, note::{ note_getter_options::NoteGetterOptions, + note_getter_options::NoteStatus, note_header::NoteHeader, utils as note_utils, }, @@ -25,23 +26,31 @@ contract InclusionProofs { history::{ contract_inclusion::{ prove_contract_inclusion, + prove_contract_inclusion_at, }, note_inclusion::{ - prove_note_commitment_inclusion, prove_note_inclusion, + prove_note_inclusion_at, }, note_validity::{ prove_note_validity, + prove_note_validity_at, }, nullifier_inclusion::{ prove_nullifier_inclusion, + prove_nullifier_inclusion_at, + prove_note_is_nullified, + prove_note_is_nullified_at, }, nullifier_non_inclusion::{ - prove_nullifier_non_inclusion, + prove_nullifier_not_included, + prove_nullifier_not_included_at, prove_note_not_nullified, + prove_note_not_nullified_at, }, public_value_inclusion::{ prove_public_value_inclusion, + prove_public_value_inclusion_at, }, }, // docs:end:imports @@ -76,79 +85,103 @@ contract InclusionProofs { } // docs:end:create_note - // Proves that the owner owned a ValueNote at block `block_number`. #[aztec(private)] - fn test_note_inclusion_proof( + fn test_note_inclusion( owner: AztecAddress, + use_block_number: bool, block_number: u32, // The block at which we'll prove that the note exists - // Value below is only used when the note is not found --> used to test the note inclusion failure case (it - // allows me to pass in random value of note nullifier - I cannot add and fetch a random note from PXE because - // PXE performs note commitment inclusion check when you add a new note). - spare_commitment: Field + nullified: bool ) { // docs:start:get_note_from_pxe // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + if (nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); + } let notes = private_values.get_notes(options); let maybe_note = notes[0]; // docs:end:get_note_from_pxe // 2) Prove the note inclusion - if maybe_note.is_some() { + if (use_block_number) { // docs:start:prove_note_inclusion - prove_note_inclusion(maybe_note.unwrap_unchecked(), block_number, context); + prove_note_inclusion_at(maybe_note.unwrap_unchecked(), block_number, context); // docs:end:prove_note_inclusion } else { - // Note was not found so we will prove inclusion of the spare commitment - prove_note_commitment_inclusion(spare_commitment, block_number, context); - }; + prove_note_inclusion(maybe_note.unwrap_unchecked(), context); + } + } + + #[aztec(private)] + fn test_note_inclusion_fail_case( + owner: AztecAddress, + use_block_number: bool, + block_number: u32 // The block at which we'll prove that the note exists + ) { + let mut note = ValueNote::new(1, owner); + + if (use_block_number) { + prove_note_inclusion_at(note, block_number, context); + } else { + prove_note_inclusion(note, context); + } } // Proves that the note was not yet nullified at block `block_number`. #[aztec(private)] - fn test_nullifier_non_inclusion_proof( + fn test_note_not_nullified( owner: AztecAddress, + use_block_number: bool, block_number: u32, // The block at which we'll prove that the nullifier does not exists // Value below is only used when the note is not found --> used to test the nullifier non-inclusion failure // case (it allows me to pass in random value of note nullifier - I cannot add and fetch a random note from PXE // because PXE performs note commitment inclusion check when you add a new note). - spare_nullifier: Field + fail_case: bool ) { // 2) Get the note from PXE let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + if (fail_case) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); + } let notes = private_values.get_notes(options); let maybe_note = notes[0]; // 3) Compute the nullifier from the note - if maybe_note.is_some() { - // docs:start:prove_note_not_nullified - prove_note_not_nullified(maybe_note.unwrap_unchecked(), block_number, &mut context); - // docs:end:prove_note_not_nullified + // docs:start:prove_note_not_nullified + if (use_block_number) { + prove_note_not_nullified_at(maybe_note.unwrap_unchecked(), block_number, &mut context); } else { - // Note was not found so we will use the spare nullifier - // docs:start:prove_nullifier_non_inclusion - prove_nullifier_non_inclusion(spare_nullifier, block_number, context); - // docs:end:prove_nullifier_non_inclusion - }; + prove_note_not_nullified(maybe_note.unwrap_unchecked(), &mut context); + } + // docs:end:prove_note_not_nullified } #[aztec(private)] - fn test_note_validity_proof( + fn test_note_validity( owner: AztecAddress, - block_number: u32 // The block at which we'll prove that the note exists and is not nullified + use_block_number: bool, + block_number: u32, // The block at which we'll prove that the note exists and is not nullified + nullified: bool ) { // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + if (nullified) { + options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); + } let notes = private_values.get_notes(options); let note = notes[0].unwrap(); // 2) Prove the note validity - // docs:start:prove_note_validity - prove_note_validity(note, block_number, &mut context); - // docs:end:prove_note_validity + if (use_block_number) { + // docs:start:prove_note_validity + prove_note_validity_at(note, block_number, &mut context); + // docs:end:prove_note_validity + } else { + prove_note_validity(note, &mut context); + } } // docs:start:nullify_note @@ -167,37 +200,54 @@ contract InclusionProofs { // Note: I am not getting a nullifier of the note that was created in this contract in this function because it is // currently not possible to obtain a nullified note from PXE. #[aztec(private)] - fn test_nullifier_inclusion_proof( + fn test_nullifier_inclusion( nullifier: Field, + use_block_number: bool, block_number: u32 // The block at which we'll prove that the nullifier not exists in the tree ) { - // docs:start:prove_nullifier_inclusion - prove_nullifier_inclusion(nullifier, block_number, context); - // docs:end:prove_nullifier_inclusion + if (use_block_number) { + // docs:start:prove_nullifier_inclusion + prove_nullifier_inclusion_at(nullifier, block_number, context); + // docs:end:prove_nullifier_inclusion + } else { + prove_nullifier_inclusion(nullifier, context); + } } #[aztec(private)] - fn test_public_unused_value_inclusion_proof(block_number: u32 // The block at which we'll prove that the public value exists + fn test_public_unused_value_inclusion(block_number: u32 // The block at which we'll prove that the public value exists ) { - prove_public_value_inclusion( + prove_public_value_inclusion_at( 0, storage.public_unused_value.storage_slot, + context.this_address(), block_number, context ); } #[aztec(private)] - fn test_public_value_inclusion_proof( + fn test_public_value_inclusion( public_value: Field, + use_block_number: bool, block_number: u32 // The block at which we'll prove that the public value exists ) { - prove_public_value_inclusion( - public_value, - storage.public_value.storage_slot, - block_number, - context - ); + if (use_block_number) { + prove_public_value_inclusion_at( + public_value, + storage.public_value.storage_slot, + context.this_address(), + block_number, + context + ); + } else { + prove_public_value_inclusion( + public_value, + storage.public_value.storage_slot, + context.this_address(), + context + ); + } } // Proves that a contract exists at block `block_number`. @@ -209,7 +259,7 @@ contract InclusionProofs { // that it is what it expects. The constructor param check is the reason of why we pass in the preimage of // contract's aztec address instead of just the address. #[aztec(private)] - fn test_contract_inclusion_proof( + fn test_contract_inclusion( public_key: GrumpkinPoint, contract_address_salt: Field, contract_class_id: ContractClassId, @@ -217,7 +267,7 @@ contract InclusionProofs { portal_contract_address: EthAddress, block_number: u32 // The block at which we'll prove that the public value exists ) { - let proven_contract_address = prove_contract_inclusion( + let proven_contract_address = prove_contract_inclusion_at( public_key, contract_address_salt, contract_class_id, diff --git a/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr b/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr index 928d80b908b..7139b9332dc 100644 --- a/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/reader_contract/src/main.nr @@ -7,7 +7,6 @@ contract Reader { use dep::compressed_string::FieldCompressedString; #[aztec(private)] - fn constructor() {} #[aztec(public)] @@ -20,7 +19,7 @@ contract Reader { } #[aztec(private)] - fn check_name_private(who: AztecAddress, what: str<31>) { + fn check_name_private(who: AztecAddress, what: str<31>) { let selector = FunctionSelector::from_signature("private_get_name()"); let ret = context.call_private_function_no_args(who, selector); let name = FieldCompressedString::from_field(ret[0]); @@ -28,6 +27,11 @@ contract Reader { assert(name.is_eq(_what)); } + unconstrained fn get_name(who: AztecAddress) -> pub str<6> { + // We cannot yet call an unconstrained function from another + "Reader" + } + #[aztec(public)] fn check_symbol_public(who: AztecAddress, what: str<31>) { let selector = FunctionSelector::from_signature("public_get_symbol()"); @@ -46,6 +50,11 @@ contract Reader { assert(symbol.is_eq(_what)); } + unconstrained fn get_symbol(who: AztecAddress) -> pub str<3> { + // We cannot yet call an unconstrained function from another + "RDR" + } + #[aztec(public)] fn check_decimals_public(who: AztecAddress, what: u8) { let selector = FunctionSelector::from_signature("public_get_decimals()"); @@ -59,4 +68,9 @@ contract Reader { let ret = context.call_private_function_no_args(who, selector); assert(ret[0] as u8 == what); } + + unconstrained fn get_decimals(who: AztecAddress) -> pub u8 { + // We cannot yet call an unconstrained function from another + 18 + } } diff --git a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index 6226024e39f..ce0c13a9844 100644 --- a/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -2,10 +2,7 @@ // Account contract that uses Schnorr signatures for authentication using a hardcoded public key. contract SchnorrHardcodedAccount { use dep::std; - use dep::aztec::{ - abi::{ PrivateCircuitPublicInputs, PrivateContextInputs, Hasher }, - context::PrivateContext, - }; + use dep::aztec::context::PrivateContext; use dep::authwit:: { entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, diff --git a/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr index ca90157034c..0b40f7ad4b3 100644 --- a/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -49,6 +49,12 @@ contract StatefulTest { increment(recipient_notes, amount, recipient); } + #[aztec(public)] + fn increment_public_value(owner: AztecAddress, value: Field) { + let loc = storage.public_values.at(owner); + loc.write(loc.read() + value); + } + unconstrained fn summed_values(owner: AztecAddress) -> pub Field { let owner_balance = storage.notes.at(owner); @@ -56,6 +62,10 @@ contract StatefulTest { balance_utils::get_balance(owner_balance) } + unconstrained fn get_public_value(owner: AztecAddress) -> pub Field { + storage.public_values.at(owner).read() + } + unconstrained fn compute_note_hash_and_nullifier( contract_address: AztecAddress, nonce: Field, diff --git a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr index ad0108f3b1f..d381bcbcfb8 100644 --- a/yarn-project/noir-contracts/contracts/test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/test_contract/src/main.nr @@ -2,6 +2,7 @@ contract Test { use dep::std::option::Option; use dep::aztec::protocol_types::{ + abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, address::{ AztecAddress, EthAddress, @@ -9,21 +10,18 @@ contract Test { constants::{ MAX_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE - } + }, + hash::hash_args, }; - // The following import is here in order to make the event macro work because the macro doesn't add the import. - // It doesn't add the import because in the future we will re-export all the types via aztec-nr and aztec-nr is - // already auto-imported by the macros. - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3590): Remove this once the issue is fixed. - use dep::aztec::protocol_types; // docs:start:unencrypted_import use dep::aztec::log::emit_unencrypted_log; // docs:end:unencrypted_import use dep::aztec::{ - context::Context, - abi, - abi::PrivateContextInputs, + context::{ + Context, + inputs::private_context_inputs::PrivateContextInputs, + }, hash::pedersen_hash, context::PrivateContext, note::{ @@ -87,7 +85,9 @@ contract Test { #[aztec(private)] fn call_create_note(value: Field, owner: AztecAddress, storage_slot: Field) { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let mut note = ValueNote::new(value, owner); create_note(&mut context, storage_slot, &mut note, true); @@ -95,7 +95,9 @@ contract Test { #[aztec(private)] fn call_get_notes(storage_slot: Field, active_or_nullified: bool) { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let mut options = NoteGetterOptions::new(); if (active_or_nullified) { @@ -112,7 +114,9 @@ contract Test { #[aztec(private)] fn call_get_notes_many(storage_slot: Field, active_or_nullified: bool) { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let mut options = NoteGetterOptions::new(); if (active_or_nullified) { @@ -128,7 +132,9 @@ contract Test { } unconstrained fn call_view_notes(storage_slot: Field, active_or_nullified: bool) -> pub Field { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let mut options = NoteViewerOptions::new(); if (active_or_nullified) { @@ -144,7 +150,9 @@ contract Test { storage_slot: Field, active_or_nullified: bool ) -> pub [Field; 2] { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let mut options = NoteViewerOptions::new(); if (active_or_nullified) { @@ -158,7 +166,9 @@ contract Test { #[aztec(private)] fn call_destroy_note(storage_slot: Field) { - assert(storage_slot != 1, "storage slot 1 is reserved for example_constant"); + assert( + storage_slot != storage.example_constant.get_storage_slot(), "this storage slot is reserved for example_constant" + ); let options = NoteGetterOptions::new(); let opt_notes: [Option; MAX_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); @@ -169,7 +179,7 @@ contract Test { } // Test codegen for Aztec.nr interfaces - // See yarn-project/acir-simulator/src/client/private_execution.test.ts 'nested calls through autogenerated interface' + // See yarn-project/simulator/src/client/private_execution.test.ts 'nested calls through autogenerated interface' // Note; this function is deliberately NOT annotated with #[aztec(private)] due to its use in tests fn test_code_gen( inputs: PrivateContextInputs, @@ -179,7 +189,7 @@ contract Test { an_array: [Field; 2], a_struct: DummyNote, a_deep_struct: DeepStruct - ) -> distinct pub abi::PrivateCircuitPublicInputs { + ) -> distinct pub PrivateCircuitPublicInputs { let mut args: BoundedVec = BoundedVec::new(0); args.push(a_field); args.push(a_bool as Field); @@ -195,7 +205,7 @@ contract Test { args.push(note.amount); args.push(note.secret_hash); } - let args_hash = abi::hash_args(args.storage); + let args_hash = hash_args(args.storage); let mut context = PrivateContext::new(inputs, args_hash); context.return_values.push(args_hash); context.finish() @@ -286,6 +296,39 @@ contract Test { storage.example_constant.initialize(&mut note, false); } + #[aztec(private)] + fn assert_private_global_vars(chain_id: Field, version: Field) { + assert(context.chain_id() == chain_id, "Invalid chain id"); + assert(context.version() == version, "Invalid version"); + } + + #[aztec(public)] + fn assert_public_global_vars( + chain_id: Field, + version: Field, + block_number: Field, + timestamp: Field, + coinbase: EthAddress, + fee_recipient: AztecAddress + ) { + assert(context.chain_id() == chain_id, "Invalid chain id"); + assert(context.version() == version, "Invalid version"); + assert(context.block_number() == block_number, "Invalid block number"); + assert(context.timestamp() == timestamp, "Invalid timestamp"); + assert(context.coinbase() == coinbase, "Invalid coinbase"); + assert(context.fee_recipient() == fee_recipient, "Invalid fee recipient"); + } + + #[aztec(private)] + fn assert_header_private(header_hash: Field) { + assert(context.historical_header.hash() == header_hash, "Invalid header hash"); + } + + #[aztec(public)] + fn assert_header_public(header_hash: Field) { + assert(context.historical_header.hash() == header_hash, "Invalid header hash"); + } + unconstrained fn get_constant() -> pub Field { let constant = storage.example_constant.view_note(); constant.value diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/main.nr b/yarn-project/noir-contracts/contracts/token_contract/src/main.nr index 01af0454f6a..1c21fd1f95a 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/main.nr @@ -22,7 +22,6 @@ contract Token { note_header::NoteHeader, utils as note_utils, }, - context::{PrivateContext, PublicContext, Context}, hash::{compute_secret_hash}, state_vars::{map::Map, public_state::PublicState, stable_public_state::StablePublicState, set::Set}, protocol_types::{ diff --git a/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 3b4c0607528..8452ba327a7 100644 --- a/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/yarn-project/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -1,8 +1,7 @@ use dep::std::option::Option; use dep::safe_math::SafeU120; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - hash::pedersen_hash, + context::Context, protocol_types::{ address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL, diff --git a/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr b/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr index 1d9c2985eb9..3db1354766b 100644 --- a/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr +++ b/yarn-project/noir-contracts/contracts/uniswap_contract/src/interfaces.nr @@ -7,7 +7,7 @@ use dep::aztec::protocol_types::{ }, }; use dep::aztec::{ - context::{ PrivateContext, PublicContext, Context }, + context::{ PrivateContext, PublicContext }, }; struct Token { diff --git a/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr b/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr index 65f9a8ea590..b389f1b3413 100644 --- a/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -14,7 +14,6 @@ contract Uniswap { }, }; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, oracle::{context::get_portal_address}, state_vars::{map::Map, public_state::PublicState}, }; diff --git a/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap index 0b402d4b977..881893d19b6 100644 --- a/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits/src/__snapshots__/index.test.ts.snap @@ -6,14 +6,57 @@ exports[`Noir compatibility tests (interop_testing.nr) Address matches Noir 1`] exports[`Noir compatibility tests (interop_testing.nr) ComputeContractAddressFromPartial matches Noir 1`] = `"0x0b487ff2900ae1178e131bfe333fdbc351beef658f7c0d62db2801429b1aab75"`; -exports[`Noir compatibility tests (interop_testing.nr) Public call stack item matches noir 1`] = `"0x037cb5ba672a7c461e23cf22ae618757ab4f1a912f3fdc93b2b2800cfe57bb91"`; +exports[`Noir compatibility tests (interop_testing.nr) Public call stack item matches noir 1`] = `"0x17095bbb9e3e104dc520b6eec9338e9b6ce1fdc0f3a66b06d5ca90b15909ad0e"`; -exports[`Noir compatibility tests (interop_testing.nr) Public call stack item request matches noir 1`] = `"0x2c36008a759d932a3a1986429aa295e2c2d4e62c33197a7d259750d29347bf30"`; +exports[`Noir compatibility tests (interop_testing.nr) Public call stack item request matches noir 1`] = `"0x28cb4c264eb11e13c77a5e60b251a6b3edfb4cfed786c4f1ec5e1749fede9b78"`; exports[`Noir compatibility tests (interop_testing.nr) Public key hash matches Noir 1`] = `"0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8"`; exports[`Noir compatibility tests (interop_testing.nr) TxRequest Hash matches Noir 1`] = `"0x0b487ff2900ae1178e131bfe333fdbc351beef658f7c0d62db2801429b1aab75"`; +exports[`Noir compatibility tests (interop_testing.nr) Var args hash matches noir 1`] = ` +Fr { + "asBigInt": 1557627899280963684159398665725097926236612957540256425197580046184563077271n, + "asBuffer": { + "data": [ + 3, + 113, + 150, + 13, + 216, + 78, + 211, + 68, + 90, + 176, + 153, + 172, + 76, + 26, + 245, + 186, + 144, + 224, + 199, + 19, + 181, + 147, + 224, + 202, + 82, + 238, + 83, + 32, + 135, + 199, + 240, + 151, + ], + "type": "Buffer", + }, +} +`; + exports[`Private kernel Executes private kernel init circuit for a contract deployment 1`] = ` KernelCircuitPublicInputs { "constants": CombinedConstantData { @@ -33187,317 +33230,505 @@ KernelCircuitPublicInputs { exports[`Private kernel Executes private kernel inner for a nested call 1`] = ` KernelCircuitPublicInputs { - "constants": CombinedConstantData { - "historicalHeader": Header { - "bodyHash": { - "data": [ - 202, - 7, - 69, - 186, - 141, - 34, - 150, - 186, - 241, - 163, - 100, - 65, - 251, - 77, - 94, - 195, - 57, - 205, - 230, - 196, - 163, - 110, - 162, - 145, - 34, - 9, - 161, - 16, - 211, - 202, - 75, - 105, - ], - "type": "Buffer", - }, - "globalVariables": { - "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", - "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065bcc7a9", - "version": "0x0000000000000000000000000000000000000000000000000000000000000001", - }, - "lastArchive": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 3, - "root": Fr { - "asBigInt": 17460993894051351766144729239097264546326076918069709472556733881494772641808n, - "asBuffer": { - "data": [ - 38, - 154, - 146, - 131, - 125, - 67, - 71, - 39, - 197, - 130, - 103, - 100, - 14, - 37, - 86, - 210, - 92, - 10, - 180, - 219, - 200, - 137, - 52, - 41, - 58, - 80, - 143, - 57, - 188, - 87, - 240, - 16, - ], - "type": "Buffer", - }, - }, - }, - "state": StateReference { - "l1ToL2MessageTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 48, - "root": Fr { - "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, - "asBuffer": { - "data": [ - 24, - 100, - 252, - 218, - 168, - 15, - 242, - 113, - 145, - 84, - 250, - 124, - 138, - 144, - 80, - 102, - 41, - 114, - 112, - 113, - 104, - 214, - 158, - 172, - 157, - 182, - 253, - 49, - 16, - 130, - 159, - 128, - ], - "type": "Buffer", - }, - }, - }, - "partial": PartialStateReference { - "contractTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 6, - "root": Fr { - "asBigInt": 7184605302455850667068570391949387715066077618994555619348936576120976120612n, - "asBuffer": { - "data": [ - 15, - 226, - 87, - 173, - 200, - 3, - 188, - 194, - 107, - 99, - 243, - 173, - 248, - 44, - 26, - 225, - 114, - 91, - 193, - 86, - 142, - 161, - 7, - 78, - 255, - 147, - 63, - 119, - 71, - 181, - 27, - 36, - ], - "type": "Buffer", - }, - }, - }, - "noteHashTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 384, - "root": Fr { - "asBigInt": 1872843773252782095434971908857689801252473218361724812174218364603162068077n, - "asBuffer": { - "data": [ - 4, - 35, - 253, - 244, - 110, - 37, - 109, - 21, - 173, - 78, - 101, - 161, - 192, - 95, - 118, - 187, - 228, - 96, - 6, - 113, - 209, - 173, - 246, - 173, - 227, - 11, - 218, - 80, - 0, - 118, - 132, - 109, - ], - "type": "Buffer", - }, - }, - }, - "nullifierTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 512, - "root": Fr { - "asBigInt": 20486647673914384391115918891411546616621428785856355813524731061605677519217n, - "asBuffer": { - "data": [ - 45, - 75, - 8, - 27, - 151, - 42, - 155, - 133, - 80, - 31, - 128, - 163, - 63, - 123, - 82, - 38, - 186, - 43, - 75, - 232, - 52, - 5, - 204, - 12, - 35, - 223, - 244, - 203, - 25, - 37, - 209, - 113, - ], - "type": "Buffer", - }, - }, - }, - "publicDataTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 128, - "root": Fr { - "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, - "asBuffer": { - "data": [ - 30, - 210, - 80, - 237, - 115, - 219, - 110, - 112, - 128, - 92, - 78, - 252, - 240, - 5, - 110, - 134, - 149, - 183, - 156, - 211, - 186, - 65, - 142, - 130, - 124, - 24, - 77, - 238, - 108, - 111, - 176, - 224, - ], - "type": "Buffer", - }, - }, - }, - }, - }, - }, - "txContext": TxContext { - "chainId": Fr { - "asBigInt": 31337n, + "aggregationObject": AggregationObject { + "hasData": false, + "p0": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "p1": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "proofWitnessIndices": [ + 3027, + 3028, + 3029, + 3030, + 3031, + 3032, + 3033, + 3034, + 3035, + 3036, + 3037, + 3038, + 3039, + 3040, + 3041, + 3042, + ], + "publicInputs": [], + }, + "constants": CombinedConstantData { + "historicalHeader": Header { + "bodyHash": { + "data": [ + 159, + 85, + 183, + 206, + 13, + 23, + 12, + 202, + 197, + 140, + 47, + 92, + 9, + 188, + 253, + 203, + 219, + 179, + 240, + 101, + 223, + 238, + 8, + 189, + 166, + 66, + 94, + 255, + 22, + 54, + 119, + 234, + ], + "type": "Buffer", + }, + "globalVariables": { + "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", + "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", + "coinbase": "0x0000000000000000000000000000000000000000", + "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065c3664a", + "version": "0x0000000000000000000000000000000000000000000000000000000000000001", + }, + "lastArchive": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 3, + "root": Fr { + "asBigInt": 9752526175035743725085774589356567288560289124217882264770841888953305498367n, + "asBuffer": { + "data": [ + 21, + 143, + 187, + 244, + 187, + 88, + 251, + 160, + 76, + 10, + 203, + 21, + 241, + 83, + 71, + 196, + 139, + 62, + 166, + 128, + 248, + 215, + 218, + 226, + 187, + 30, + 59, + 12, + 75, + 225, + 130, + 255, + ], + "type": "Buffer", + }, + }, + }, + "state": StateReference { + "l1ToL2MessageTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 48, + "root": Fr { + "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, + "asBuffer": { + "data": [ + 24, + 100, + 252, + 218, + 168, + 15, + 242, + 113, + 145, + 84, + 250, + 124, + 138, + 144, + 80, + 102, + 41, + 114, + 112, + 113, + 104, + 214, + 158, + 172, + 157, + 182, + 253, + 49, + 16, + 130, + 159, + 128, + ], + "type": "Buffer", + }, + }, + }, + "partial": PartialStateReference { + "contractTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 6, + "root": Fr { + "asBigInt": 1615603088022677818890278836908782753125220652207319187619222416535409782483n, + "asBuffer": { + "data": [ + 3, + 146, + 102, + 33, + 28, + 147, + 252, + 76, + 143, + 201, + 189, + 110, + 139, + 224, + 38, + 79, + 86, + 59, + 12, + 111, + 14, + 249, + 39, + 210, + 172, + 29, + 46, + 118, + 173, + 241, + 238, + 211, + ], + "type": "Buffer", + }, + }, + }, + "noteHashTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 384, + "root": Fr { + "asBigInt": 8025063940971333475794771983566777251236321183295948316041170713437994278029n, + "asBuffer": { + "data": [ + 17, + 190, + 6, + 117, + 75, + 140, + 35, + 43, + 139, + 173, + 157, + 218, + 53, + 234, + 11, + 200, + 32, + 49, + 144, + 145, + 133, + 123, + 13, + 98, + 225, + 46, + 88, + 97, + 142, + 140, + 220, + 141, + ], + "type": "Buffer", + }, + }, + }, + "nullifierTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 512, + "root": Fr { + "asBigInt": 18048048738552584986776596366964943842863658371345218458771486548382455209761n, + "asBuffer": { + "data": [ + 39, + 230, + 213, + 101, + 227, + 179, + 100, + 70, + 49, + 60, + 205, + 28, + 44, + 191, + 212, + 245, + 244, + 198, + 102, + 146, + 255, + 38, + 25, + 187, + 138, + 42, + 230, + 204, + 252, + 180, + 159, + 33, + ], + "type": "Buffer", + }, + }, + }, + "publicDataTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 128, + "root": Fr { + "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, + "asBuffer": { + "data": [ + 30, + 210, + 80, + 237, + 115, + 219, + 110, + 112, + 128, + 92, + 78, + 252, + 240, + 5, + 110, + 134, + 149, + 183, + 156, + 211, + 186, + 65, + 142, + 130, + 124, + 24, + 77, + 238, + 108, + 111, + 176, + 224, + ], + "type": "Buffer", + }, + }, + }, + }, + }, + }, + "txContext": TxContext { + "chainId": Fr { + "asBigInt": 31337n, "asBuffer": { "data": [ 0, @@ -33814,11 +34045,132 @@ KernelCircuitPublicInputs { }, }, "end": CombinedAccumulatedData { - "aggregationObject": AggregationObject { - "hasData": false, - "p0": G1AffineElement { - "x": Fq { - "asBigInt": 1n, + "encryptedLogPreimagesLength": Fr { + "asBigInt": 12n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 12, + ], + "type": "Buffer", + }, + }, + "encryptedLogsHash": [ + Fr { + "asBigInt": 10654334908029642268226261618939201427n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 3, + 243, + 68, + 123, + 49, + 16, + 181, + 87, + 150, + 38, + 199, + 134, + 29, + 7, + 147, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 133338275028334099210129003420909668908n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 100, + 80, + 4, + 133, + 110, + 109, + 121, + 70, + 184, + 235, + 48, + 170, + 28, + 9, + 138, + 44, + ], + "type": "Buffer", + }, + }, + ], + "newCommitments": [ + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33852,13 +34204,13 @@ KernelCircuitPublicInputs { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, }, - "y": Fq { - "asBigInt": 2n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -33892,237 +34244,12 @@ KernelCircuitPublicInputs { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, }, }, - "p1": G1AffineElement { - "x": Fq { - "asBigInt": 1n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 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, - ], - "type": "Buffer", - }, - }, - "y": Fq { - "asBigInt": 2n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 2, - ], - "type": "Buffer", - }, - }, - }, - "proofWitnessIndices": [ - 3027, - 3028, - 3029, - 3030, - 3031, - 3032, - 3033, - 3034, - 3035, - 3036, - 3037, - 3038, - 3039, - 3040, - 3041, - 3042, - ], - "publicInputs": [], - }, - "encryptedLogPreimagesLength": Fr { - "asBigInt": 12n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 12, - ], - "type": "Buffer", - }, - }, - "encryptedLogsHash": [ - Fr { - "asBigInt": 10654334908029642268226261618939201427n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 8, - 3, - 243, - 68, - 123, - 49, - 16, - 181, - 87, - 150, - 38, - 199, - 134, - 29, - 7, - 147, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 133338275028334099210129003420909668908n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 100, - 80, - 4, - 133, - 110, - 109, - 121, - 70, - 184, - 235, - 48, - 170, - 28, - 9, - 138, - 44, - ], - "type": "Buffer", - }, - }, - ], - "newCommitments": [ SideEffect { "counter": Fr { "asBigInt": 0n, @@ -39289,92 +39416,10 @@ KernelCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "value": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - ], - "newContracts": [ - NewContractData { - "contractAddress": AztecAddress { + ], + "newContracts": [ + NewContractData { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -39648,41 +39693,41 @@ KernelCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 19892533414055040205853494828414910286665152661907689787879613993751150400169n, + "asBigInt": 7282259706960784487808381312888935962471943947178183177649973507966566928562n, "asBuffer": { "data": [ - 43, - 250, - 198, - 96, - 235, - 243, - 57, - 48, - 186, - 157, - 124, - 176, - 6, - 34, - 154, - 77, - 241, - 211, - 154, - 21, - 205, + 16, + 25, + 156, + 232, + 245, + 169, + 188, + 68, 47, - 108, - 121, - 234, - 120, - 44, - 230, - 246, - 221, - 18, + 55, + 174, + 23, + 5, + 152, 169, + 188, + 144, + 209, + 126, + 173, + 171, + 101, + 129, + 119, + 156, + 150, + 118, + 160, + 229, + 96, + 16, + 178, ], "type": "Buffer", }, @@ -48037,9 +48082,91 @@ KernelCircuitPublicInputs { }, }, ], - "optionallyRevealedData": [ - OptionallyRevealedData { - "callStackItemHash": Fr { + "privateCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48079,46 +48206,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "vkHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48158,9 +48246,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - OptionallyRevealedData { - "callStackItemHash": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48200,20 +48286,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "startSideEffectCounter": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -48235,11 +48310,107 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48279,9 +48450,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - OptionallyRevealedData { - "callStackItemHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48321,20 +48490,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "hash": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -48356,11 +48514,23 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48401,8 +48571,90 @@ KernelCircuitPublicInputs { }, }, }, - OptionallyRevealedData { - "callStackItemHash": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48442,20 +48694,49 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, + "endSideEffectCounter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "hash": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -48477,11 +48758,23 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -48522,8 +48815,6 @@ KernelCircuitPublicInputs { }, }, }, - ], - "privateCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -49744,6 +50035,8 @@ KernelCircuitPublicInputs { }, }, }, + ], + "publicCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -50476,8 +50769,6 @@ KernelCircuitPublicInputs { }, }, }, - ], - "publicCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -51698,170 +51989,10 @@ KernelCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "endSideEffectCounter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "hash": Fr { + ], + "publicDataReads": [ + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -51901,7 +52032,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -51942,90 +52074,8 @@ KernelCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52065,7 +52115,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52105,7 +52156,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52145,7 +52198,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52186,90 +52240,8 @@ KernelCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52309,7 +52281,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52349,7 +52322,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52389,7 +52364,8 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "sideEffectCounter": undefined, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -52430,8 +52406,6 @@ KernelCircuitPublicInputs { }, }, }, - ], - "publicDataReads": [ PublicDataRead { "leafSlot": Fr { "asBigInt": 0n, @@ -53345,7 +53319,9 @@ KernelCircuitPublicInputs { }, }, }, - PublicDataRead { + ], + "publicDataUpdateRequests": [ + PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -53386,8 +53362,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53427,8 +53402,49 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "oldValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "sideEffectCounter": undefined, }, - PublicDataRead { + PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -53469,8 +53485,47 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "newValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "oldValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53510,8 +53565,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - PublicDataRead { + PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -53552,8 +53608,47 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "newValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "oldValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53593,8 +53688,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - PublicDataRead { + PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { @@ -53635,8 +53731,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53676,9 +53771,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - }, - PublicDataRead { - "leafSlot": Fr { + "oldValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53719,7 +53812,9 @@ KernelCircuitPublicInputs { }, }, "sideEffectCounter": undefined, - "value": Fr { + }, + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -53759,9 +53854,88 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, + "newValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "oldValue": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "sideEffectCounter": undefined, }, - ], - "publicDataUpdateRequests": [ PublicDataUpdateRequest { "leafSlot": Fr { "asBigInt": 0n, @@ -55115,8 +55289,10 @@ KernelCircuitPublicInputs { }, "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + ], + "readRequests": [ + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55156,7 +55332,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55196,7 +55372,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "oldValue": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55236,10 +55414,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55279,7 +55454,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55319,7 +55496,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "oldValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55359,10 +55536,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55402,7 +55578,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55442,7 +55618,49 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "oldValue": Fr { + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55482,10 +55700,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55525,7 +55742,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55565,7 +55782,49 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "oldValue": Fr { + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55605,10 +55864,9 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55648,7 +55906,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55688,7 +55946,49 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "oldValue": Fr { + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -55728,10 +56028,7 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - ], - "readRequests": [ SideEffect { "counter": Fr { "asBigInt": 0n, @@ -65490,8 +65787,412 @@ KernelCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "unencryptedLogPreimagesLength": Fr { + "asBigInt": 12n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 12, + ], + "type": "Buffer", + }, + }, + "unencryptedLogsHash": [ + Fr { + "asBigInt": 10654334908029642268226261618939201427n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 8, + 3, + 243, + 68, + 123, + 49, + 16, + 181, + 87, + 150, + 38, + 199, + 134, + 29, + 7, + 147, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 133338275028334099210129003420909668908n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 100, + 80, + 4, + 133, + 110, + 109, + 121, + 70, + 184, + 235, + 48, + 170, + 28, + 9, + 138, + 44, + ], + "type": "Buffer", + }, + }, + ], + }, + "isPrivate": true, + "metaHwm": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, +} +`; + +exports[`Private kernel Executes private kernel ordering after a deployment 1`] = ` +KernelCircuitPublicInputsFinal { + "aggregationObject": AggregationObject { + "hasData": false, + "p0": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "p1": G1AffineElement { + "x": Fq { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "y": Fq { + "asBigInt": 2n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 2, + ], + "type": "Buffer", + }, + }, + }, + "proofWitnessIndices": [ + 3027, + 3028, + 3029, + 3030, + 3031, + 3032, + 3033, + 3034, + 3035, + 3036, + 3037, + 3038, + 3039, + 3040, + 3041, + 3042, + ], + "publicInputs": [], + }, + "constants": CombinedConstantData { + "historicalHeader": Header { + "bodyHash": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + "globalVariables": { + "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000000", + "chainId": "0x0000000000000000000000000000000000000000000000000000000000000000", + "coinbase": "0x0000000000000000000000000000000000000000", + "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000000000000", + "version": "0x0000000000000000000000000000000000000000000000000000000000000000", + }, + "lastArchive": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 0, + "root": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -65531,10 +66232,396 @@ KernelCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 0n, + }, + "state": StateReference { + "l1ToL2MessageTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 0, + "root": Fr { + "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, + "asBuffer": { + "data": [ + 24, + 100, + 252, + 218, + 168, + 15, + 242, + 113, + 145, + 84, + 250, + 124, + 138, + 144, + 80, + 102, + 41, + 114, + 112, + 113, + 104, + 214, + 158, + 172, + 157, + 182, + 253, + 49, + 16, + 130, + 159, + 128, + ], + "type": "Buffer", + }, + }, + }, + "partial": PartialStateReference { + "contractTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 0, + "root": Fr { + "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, + "asBuffer": { + "data": [ + 24, + 100, + 252, + 218, + 168, + 15, + 242, + 113, + 145, + 84, + 250, + 124, + 138, + 144, + 80, + 102, + 41, + 114, + 112, + 113, + 104, + 214, + 158, + 172, + 157, + 182, + 253, + 49, + 16, + 130, + 159, + 128, + ], + "type": "Buffer", + }, + }, + }, + "noteHashTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 0, + "root": Fr { + "asBigInt": 10127882181290008410413105921460858232892226592306749913988016925836213768395n, + "asBuffer": { + "data": [ + 22, + 100, + 45, + 156, + 205, + 131, + 70, + 196, + 3, + 170, + 76, + 63, + 164, + 81, + 23, + 139, + 34, + 83, + 74, + 39, + 3, + 92, + 218, + 166, + 236, + 52, + 174, + 83, + 178, + 156, + 80, + 203, + ], + "type": "Buffer", + }, + }, + }, + "nullifierTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 128, + "root": Fr { + "asBigInt": 5342309968596764527275045470866818007603635181649161546597860399861598581368n, + "asBuffer": { + "data": [ + 11, + 207, + 163, + 233, + 241, + 168, + 146, + 46, + 233, + 44, + 109, + 201, + 100, + 214, + 89, + 89, + 7, + 193, + 128, + 74, + 134, + 117, + 55, + 116, + 50, + 43, + 70, + 143, + 105, + 212, + 242, + 120, + ], + "type": "Buffer", + }, + }, + }, + "publicDataTree": AppendOnlyTreeSnapshot { + "nextAvailableLeafIndex": 32, + "root": Fr { + "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, + "asBuffer": { + "data": [ + 30, + 210, + 80, + 237, + 115, + 219, + 110, + 112, + 128, + 92, + 78, + 252, + 240, + 5, + 110, + 134, + 149, + 183, + 156, + 211, + 186, + 65, + 142, + 130, + 124, + 24, + 77, + 238, + 108, + 111, + 176, + 224, + ], + "type": "Buffer", + }, + }, + }, + }, + }, + }, + "txContext": TxContext { + "chainId": Fr { + "asBigInt": 31337n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 122, + 105, + ], + "type": "Buffer", + }, + }, + "contractDeploymentData": ContractDeploymentData { + "contractAddressSalt": Fr { + "asBigInt": 8544187673238214496875689801072975260441235376307404116118545893620678068134n, + "asBuffer": { + "data": [ + 18, + 227, + 214, + 190, + 179, + 184, + 32, + 236, + 95, + 177, + 241, + 1, + 66, + 60, + 85, + 200, + 245, + 86, + 126, + 178, + 106, + 140, + 252, + 158, + 152, + 125, + 198, + 171, + 102, + 67, + 7, + 166, + ], + "type": "Buffer", + }, + }, + "contractClassId": Fr { + "asBigInt": 20318996550496802327349100477480582836618155623061410223552429946501110360663n, + "asBuffer": { + "data": [ + 44, + 236, + 36, + 253, + 207, + 26, + 31, + 209, + 233, + 127, + 255, + 232, + 195, + 50, + 123, + 34, + 129, + 11, + 26, + 168, + 32, + 113, + 14, + 68, + 174, + 117, + 122, + 165, + 86, + 26, + 234, + 87, + ], + "type": "Buffer", + }, + }, + "initializationHash": Fr { + "asBigInt": 6600580131458695080962047164752478972501673508240453898175734878301388714873n, "asBuffer": { "data": [ + 14, + 151, + 203, + 196, + 55, + 149, + 8, + 67, + 56, + 209, + 46, + 10, + 24, + 151, + 247, + 18, + 238, + 154, + 181, + 182, + 204, + 150, + 56, + 122, + 175, + 17, + 0, + 218, + 171, + 6, + 179, + 121, + ], + "type": "Buffer", + }, + }, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, 0, 0, 0, @@ -65551,6 +66638,281 @@ KernelCircuitPublicInputs { 0, 0, 0, + ], + "type": "Buffer", + }, + }, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 20997482654787910730197747092201115844022981028868354477774601720044462620106n, + "asBuffer": { + "data": [ + 46, + 108, + 39, + 110, + 30, + 244, + 117, + 95, + 111, + 218, + 20, + 52, + 36, + 88, + 93, + 125, + 219, + 128, + 24, + 222, + 151, + 139, + 26, + 252, + 149, + 110, + 225, + 121, + 106, + 229, + 61, + 202, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 6258622076684102244410764244812736056447073443302722047654973743467608943788n, + "asBuffer": { + "data": [ + 13, + 214, + 65, + 43, + 4, + 67, + 3, + 109, + 76, + 124, + 154, + 101, + 221, + 147, + 138, + 31, + 47, + 182, + 162, + 253, + 218, + 27, + 113, + 98, + 146, + 153, + 166, + 0, + 84, + 8, + 44, + 172, + ], + "type": "Buffer", + }, + }, + }, + }, + "isContractDeploymentTx": true, + "isFeePaymentTx": false, + "isRebatePaymentTx": false, + "version": Fr { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + }, + }, + "end": FinalAccumulatedData { + "encryptedLogPreimagesLength": Fr { + "asBigInt": 248n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 248, + ], + "type": "Buffer", + }, + }, + "encryptedLogsHash": [ + Fr { + "asBigInt": 217294884204978999010662201700087440481n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 163, + 121, + 120, + 240, + 220, + 129, + 191, + 21, + 133, + 27, + 226, + 103, + 77, + 167, + 36, + 97, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 18076537616370845041336398629891292698n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 13, + 153, + 106, + 29, + 60, + 171, + 123, + 125, + 198, + 243, + 2, + 36, + 92, + 189, + 62, + 26, + ], + "type": "Buffer", + }, + }, + ], + "newCommitments": [ + SideEffect { + "counter": Fr { + "asBigInt": 3n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, @@ -65567,6 +66929,49 @@ KernelCircuitPublicInputs { 0, 0, 0, + 0, + 0, + 3, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 5687726767847307777652513305038358951349254332784681292588121100857341339419n, + "asBuffer": { + "data": [ + 12, + 147, + 35, + 167, + 27, + 119, + 44, + 190, + 133, + 195, + 47, + 204, + 238, + 51, + 148, + 114, + 83, + 239, + 180, + 149, + 110, + 180, + 235, + 90, + 51, + 190, + 155, + 155, + 193, + 3, + 103, + 27, ], "type": "Buffer", }, @@ -66228,184 +67633,8 @@ KernelCircuitPublicInputs { }, }, }, - ], - "unencryptedLogPreimagesLength": Fr { - "asBigInt": 12n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 12, - ], - "type": "Buffer", - }, - }, - "unencryptedLogsHash": [ - Fr { - "asBigInt": 10654334908029642268226261618939201427n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 8, - 3, - 243, - 68, - 123, - 49, - 16, - 181, - 87, - 150, - 38, - 199, - 134, - 29, - 7, - 147, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 133338275028334099210129003420909668908n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 100, - 80, - 4, - 133, - 110, - 109, - 121, - 70, - 184, - 235, - 48, - 170, - 28, - 9, - 138, - 44, - ], - "type": "Buffer", - }, - }, - ], - }, - "isPrivate": true, -} -`; - -exports[`Private kernel Executes private kernel ordering after a deployment 1`] = ` -KernelCircuitPublicInputsFinal { - "constants": CombinedConstantData { - "historicalHeader": Header { - "bodyHash": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - "globalVariables": { - "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000000", - "chainId": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000000000000", - "version": "0x0000000000000000000000000000000000000000000000000000000000000000", - }, - "lastArchive": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 0, - "root": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -66445,391 +67674,133 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - "state": StateReference { - "l1ToL2MessageTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 0, - "root": Fr { - "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, - "asBuffer": { - "data": [ - 24, - 100, - 252, - 218, - 168, - 15, - 242, - 113, - 145, - 84, - 250, - 124, - 138, - 144, - 80, - 102, - 41, - 114, - 112, - 113, - 104, - 214, - 158, - 172, - 157, - 182, - 253, - 49, - 16, - 130, - 159, - 128, - ], - "type": "Buffer", - }, - }, - }, - "partial": PartialStateReference { - "contractTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 0, - "root": Fr { - "asBigInt": 11033938207523021649122316027295742559227608161317650429835019071130941169536n, - "asBuffer": { - "data": [ - 24, - 100, - 252, - 218, - 168, - 15, - 242, - 113, - 145, - 84, - 250, - 124, - 138, - 144, - 80, - 102, - 41, - 114, - 112, - 113, - 104, - 214, - 158, - 172, - 157, - 182, - 253, - 49, - 16, - 130, - 159, - 128, - ], - "type": "Buffer", - }, - }, - }, - "noteHashTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 0, - "root": Fr { - "asBigInt": 10127882181290008410413105921460858232892226592306749913988016925836213768395n, - "asBuffer": { - "data": [ - 22, - 100, - 45, - 156, - 205, - 131, - 70, - 196, - 3, - 170, - 76, - 63, - 164, - 81, - 23, - 139, - 34, - 83, - 74, - 39, - 3, - 92, - 218, - 166, - 236, - 52, - 174, - 83, - 178, - 156, - 80, - 203, - ], - "type": "Buffer", - }, - }, - }, - "nullifierTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 128, - "root": Fr { - "asBigInt": 5342309968596764527275045470866818007603635181649161546597860399861598581368n, - "asBuffer": { - "data": [ - 11, - 207, - 163, - 233, - 241, - 168, - 146, - 46, - 233, - 44, - 109, - 201, - 100, - 214, - 89, - 89, - 7, - 193, - 128, - 74, - 134, - 117, - 55, - 116, - 50, - 43, - 70, - 143, - 105, - 212, - 242, - 120, - ], - "type": "Buffer", - }, - }, - }, - "publicDataTree": AppendOnlyTreeSnapshot { - "nextAvailableLeafIndex": 32, - "root": Fr { - "asBigInt": 13940981882517738105981911020707002777955674699044852872880094407282064863456n, - "asBuffer": { - "data": [ - 30, - 210, - 80, - 237, - 115, - 219, - 110, - 112, - 128, - 92, - 78, - 252, - 240, - 5, - 110, - 134, - 149, - 183, - 156, - 211, - 186, - 65, - 142, - 130, - 124, - 24, - 77, - 238, - 108, - 111, - 176, - 224, - ], - "type": "Buffer", - }, - }, - }, - }, - }, - }, - "txContext": TxContext { - "chainId": Fr { - "asBigInt": 31337n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 122, - 105, - ], - "type": "Buffer", - }, - }, - "contractDeploymentData": ContractDeploymentData { - "contractAddressSalt": Fr { - "asBigInt": 18299716421634001506677264643029159859571433729634397949479100377200296889738n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ - 40, - 117, - 69, - 191, - 17, - 209, - 153, - 95, - 48, - 16, - 234, - 239, - 253, - 140, - 7, - 167, - 73, - 225, - 5, - 221, - 243, - 8, - 29, - 115, - 66, - 74, - 72, - 180, - 31, - 122, - 141, - 138, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "contractClassId": Fr { - "asBigInt": 706408204694249493136160489878472914651446943081110537871481930811333381n, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, 0, - 102, - 90, - 34, - 246, - 189, - 224, - 165, - 168, - 12, - 122, - 203, - 2, - 212, - 172, - 183, - 114, - 219, - 254, - 78, - 17, - 126, - 177, - 66, - 101, - 61, - 70, - 180, - 178, - 91, - 5, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "initializationHash": Fr { - "asBigInt": 17785809827166439701487889277483439021145971326301684889277864426887573371434n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ - 39, - 82, - 105, - 96, - 15, - 15, - 46, - 166, - 243, - 185, - 46, - 22, - 238, - 215, - 127, - 130, - 148, - 71, - 195, - 226, - 109, - 237, - 240, - 218, - 120, - 90, - 218, - 133, - 76, - 239, - 122, - 42, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "portalContractAddress": EthAddress { - "buffer": { + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -66851,145 +67822,66 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 12152531144096508024170178545925948736773548735762044182409688360548522060769n, - "asBuffer": { - "data": [ - 26, - 222, - 22, - 192, - 169, - 57, - 102, - 235, - 213, - 208, - 34, - 176, - 132, - 135, - 68, - 67, - 0, - 127, - 198, - 131, - 77, - 141, - 178, - 9, - 77, - 151, - 74, - 96, - 68, - 144, - 235, - 225, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 16253825971304818228484711432778589826761387327039829460170834130258948952286n, - "asBuffer": { - "data": [ - 35, - 239, - 86, - 232, - 166, - 80, - 161, - 125, - 139, - 164, - 181, - 243, - 133, - 98, - 206, - 187, - 137, - 222, - 13, - 238, - 6, - 128, - 13, - 41, - 212, - 163, - 112, - 149, - 185, - 246, - 144, - 222, - ], - "type": "Buffer", - }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, }, - "isContractDeploymentTx": true, - "isFeePaymentTx": false, - "isRebatePaymentTx": false, - "version": Fr { - "asBigInt": 1n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 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, - ], - "type": "Buffer", - }, - }, - }, - }, - "end": FinalAccumulatedData { - "aggregationObject": AggregationObject { - "hasData": false, - "p0": G1AffineElement { - "x": Fq { - "asBigInt": 1n, + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -67023,13 +67915,13 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, }, - "y": Fq { - "asBigInt": 2n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -67063,15 +67955,15 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, }, }, - "p1": G1AffineElement { - "x": Fq { - "asBigInt": 1n, + SideEffect { + "counter": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -67105,13 +67997,13 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, }, - "y": Fq { - "asBigInt": 2n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -67145,158 +68037,15 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, }, }, - "proofWitnessIndices": [ - 3027, - 3028, - 3029, - 3030, - 3031, - 3032, - 3033, - 3034, - 3035, - 3036, - 3037, - 3038, - 3039, - 3040, - 3041, - 3042, - ], - "publicInputs": [], - }, - "encryptedLogPreimagesLength": Fr { - "asBigInt": 248n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 248, - ], - "type": "Buffer", - }, - }, - "encryptedLogsHash": [ - Fr { - "asBigInt": 113485459350374230794145729572631796833n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 85, - 96, - 129, - 35, - 20, - 184, - 71, - 67, - 125, - 182, - 126, - 178, - 135, - 228, - 220, - 97, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 232529322963442709284134641966020129759n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 174, - 239, - 132, - 195, - 65, - 1, - 88, - 62, - 242, - 64, - 10, - 170, - 18, - 141, - 115, - 223, - ], - "type": "Buffer", - }, - }, - ], - "newCommitments": [ SideEffect { "counter": Fr { - "asBigInt": 3n, + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -67330,47 +68079,47 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 3, + 0, ], "type": "Buffer", }, }, "value": Fr { - "asBigInt": 21621488125566733552137718714597662254857982771250066216264871247473941915958n, + "asBigInt": 0n, "asBuffer": { "data": [ - 47, - 205, - 84, - 31, - 108, - 117, - 192, - 60, - 194, - 58, - 225, - 79, - 220, - 110, - 128, - 26, - 193, - 69, - 52, - 186, - 249, - 73, - 113, - 109, - 110, - 232, - 44, - 87, - 107, - 227, - 169, - 54, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, @@ -71394,7 +72143,202 @@ KernelCircuitPublicInputsFinal { }, }, }, - SideEffect { + ], + "newContracts": [ + NewContractData { + "contractAddress": AztecAddress { + "asBigInt": 1831798284757241565498321533262051709180765196304645465118411086287998816179n, + "asBuffer": { + "data": [ + 4, + 12, + 194, + 214, + 165, + 122, + 158, + 215, + 13, + 224, + 91, + 168, + 56, + 243, + 98, + 55, + 176, + 253, + 137, + 164, + 69, + 75, + 213, + 118, + 156, + 252, + 183, + 10, + 181, + 236, + 15, + 179, + ], + "type": "Buffer", + }, + }, + "contractClassId": Fr { + "asBigInt": 20318996550496802327349100477480582836618155623061410223552429946501110360663n, + "asBuffer": { + "data": [ + 44, + 236, + 36, + 253, + 207, + 26, + 31, + 209, + 233, + 127, + 255, + 232, + 195, + 50, + 123, + 34, + 129, + 11, + 26, + 168, + 32, + 113, + 14, + 68, + 174, + 117, + 122, + 165, + 86, + 26, + 234, + 87, + ], + "type": "Buffer", + }, + }, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "newL2ToL1Msgs": [ + Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + ], + "newNullifiers": [ + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -71435,7 +72379,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71475,10 +72419,50 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, + "value": Fr { + "asBigInt": 16237374074162232692992102035008756777370701254183033524986273046870900987732n, + "asBuffer": { + "data": [ + 35, + 230, + 7, + 45, + 222, + 115, + 134, + 129, + 102, + 89, + 8, + 196, + 157, + 42, + 30, + 13, + 54, + 136, + 210, + 235, + 92, + 104, + 168, + 45, + 252, + 4, + 158, + 62, + 50, + 189, + 215, + 84, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { - "asBigInt": 0n, + "asBigInt": 1n, "asBuffer": { "data": [ 0, @@ -71512,12 +72496,12 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 0, + 1, ], "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71557,10 +72541,50 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, + "value": Fr { + "asBigInt": 14002679916261727689081875718994679854936244053750127743046108247853910743517n, + "asBuffer": { + "data": [ + 30, + 245, + 60, + 104, + 183, + 13, + 170, + 97, + 250, + 71, + 64, + 199, + 29, + 67, + 131, + 106, + 139, + 122, + 81, + 25, + 106, + 56, + 244, + 168, + 15, + 151, + 65, + 68, + 133, + 100, + 89, + 221, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { - "asBigInt": 0n, + "asBigInt": 2n, "asBuffer": { "data": [ 0, @@ -71594,12 +72618,12 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 0, + 2, ], "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71639,8 +72663,48 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, + "value": Fr { + "asBigInt": 20063831460273291822483770412375973880544120500842596637227885402045466007231n, + "asBuffer": { + "data": [ + 44, + 91, + 185, + 230, + 150, + 136, + 35, + 145, + 117, + 51, + 221, + 146, + 176, + 211, + 6, + 108, + 71, + 82, + 112, + 132, + 74, + 183, + 132, + 61, + 180, + 182, + 132, + 227, + 105, + 51, + 214, + 191, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -71681,7 +72745,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71721,9 +72785,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71763,7 +72825,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71803,9 +72867,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71886,7 +72948,7 @@ KernelCircuitPublicInputsFinal { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -71927,7 +72989,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -71967,9 +73029,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72009,7 +73069,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72049,9 +73111,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72132,7 +73192,7 @@ KernelCircuitPublicInputsFinal { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -72173,7 +73233,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72213,9 +73273,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72255,7 +73313,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72295,9 +73355,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72378,7 +73436,7 @@ KernelCircuitPublicInputsFinal { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -72419,7 +73477,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72459,9 +73517,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72501,7 +73557,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -72541,93 +73599,62 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - ], - "newContracts": [ - NewContractData { - "contractAddress": AztecAddress { - "asBigInt": 12716359170374397712580533544188622734424306722847307016455825923713560043202n, + "noteHash": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ - 28, - 29, - 52, - 72, - 125, - 180, - 55, 0, - 129, - 20, - 16, - 241, - 18, - 62, - 104, - 44, - 82, - 226, - 193, - 86, - 126, - 3, - 34, - 100, - 124, - 254, - 163, - 130, - 110, - 13, - 94, - 194, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "contractClassId": Fr { - "asBigInt": 706408204694249493136160489878472914651446943081110537871481930811333381n, + "value": Fr { + "asBigInt": 0n, "asBuffer": { "data": [ 0, 0, - 102, - 90, - 34, - 246, - 189, - 224, - 165, - 168, - 12, - 122, - 203, - 2, - 212, - 172, - 183, - 114, - 219, - 254, - 78, - 17, - 126, - 177, - 66, - 101, - 61, - 70, - 180, - 178, - 91, - 5, - ], - "type": "Buffer", - }, - }, - "portalContractAddress": EthAddress { - "buffer": { - "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, @@ -72653,90 +73680,6 @@ KernelCircuitPublicInputsFinal { }, }, }, - ], - "newL2ToL1Msgs": [ - Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - ], - "newNullifiers": [ SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, @@ -72819,41 +73762,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 5971642321292246232195213901735887805654630098701109993783053042840646156067n, + "asBigInt": 0n, "asBuffer": { "data": [ - 13, - 51, - 212, - 108, - 71, - 70, - 222, - 24, - 66, - 62, - 41, - 66, - 48, - 187, - 48, - 55, - 54, - 163, - 255, - 251, - 222, - 159, - 53, - 223, - 213, - 176, - 139, - 205, - 149, - 19, - 127, - 35, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, @@ -72861,7 +73804,7 @@ KernelCircuitPublicInputsFinal { }, SideEffectLinkedToNoteHash { "counter": Fr { - "asBigInt": 1n, + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -72895,7 +73838,7 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 1, + 0, ], "type": "Buffer", }, @@ -72941,41 +73884,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 13153902150945335774736935481185705410565795816912799539978672027283135743715n, + "asBigInt": 0n, "asBuffer": { "data": [ - 29, - 20, - 216, - 67, - 163, - 101, - 159, - 211, - 195, - 19, - 68, - 94, - 30, - 61, - 176, - 112, - 221, - 224, - 110, - 144, - 65, - 245, - 246, - 94, - 200, - 146, - 255, - 224, - 24, - 149, - 70, - 227, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, @@ -72983,7 +73926,7 @@ KernelCircuitPublicInputsFinal { }, SideEffectLinkedToNoteHash { "counter": Fr { - "asBigInt": 2n, + "asBigInt": 0n, "asBuffer": { "data": [ 0, @@ -73017,7 +73960,7 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, - 2, + 0, ], "type": "Buffer", }, @@ -73063,41 +74006,41 @@ KernelCircuitPublicInputsFinal { }, }, "value": Fr { - "asBigInt": 4602541959810880166503325519705238923914270857244686930089288097410907185175n, + "asBigInt": 0n, "asBuffer": { "data": [ - 10, - 44, - 242, - 73, - 118, - 22, - 22, - 208, - 147, - 16, - 115, - 171, - 30, - 196, - 70, - 181, - 151, - 114, - 237, - 96, - 33, - 133, - 100, - 250, - 7, - 98, - 139, - 136, - 94, - 217, - 32, - 23, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, @@ -78512,7 +79455,89 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78552,7 +79577,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78592,9 +79617,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78634,7 +79657,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78674,7 +79699,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78714,9 +79739,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78756,7 +79779,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78796,7 +79821,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78836,9 +79861,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78878,7 +79901,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78918,7 +79943,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -78958,9 +79983,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79000,7 +80023,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79040,7 +80065,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79080,9 +80105,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79122,47 +80145,93 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + }, + ], + "privateCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79202,9 +80271,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79244,7 +80311,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79284,7 +80351,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79324,9 +80391,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79366,7 +80515,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79406,7 +80555,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79446,9 +80595,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79488,47 +80635,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79568,9 +80759,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79610,7 +80799,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79650,7 +80839,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79691,8 +80880,90 @@ KernelCircuitPublicInputsFinal { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79732,7 +81003,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79772,7 +81043,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79812,9 +81083,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79854,7 +81123,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79894,7 +81247,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79934,9 +81287,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -79976,7 +81327,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80016,7 +81367,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80056,9 +81491,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80098,7 +81531,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80138,7 +81571,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80178,9 +81611,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80220,7 +81735,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80260,7 +81775,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80300,9 +81815,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80342,7 +81855,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80382,7 +81979,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80422,9 +82019,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80464,7 +82059,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "noteHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80504,7 +82099,93 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "value": Fr { + }, + ], + "publicCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80544,11 +82225,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - ], - "optionallyRevealedData": [ - OptionallyRevealedData { - "callStackItemHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80588,20 +82265,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "hash": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -80623,11 +82289,23 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80668,8 +82346,90 @@ KernelCircuitPublicInputsFinal { }, }, }, - OptionallyRevealedData { - "callStackItemHash": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80709,20 +82469,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "endSideEffectCounter": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -80744,11 +82493,23 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80788,9 +82549,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - OptionallyRevealedData { - "callStackItemHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80830,46 +82589,91 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "vkHash": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80909,9 +82713,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - OptionallyRevealedData { - "callStackItemHash": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -80951,20 +82753,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "calledFromL1": false, - "calledFromPublicL2": false, - "functionData": FunctionData { - "isConstructor": false, - "isInternal": false, - "isPrivate": false, - "selector": FunctionSelector { - "value": 0, - }, - }, - "payFeeFromL1": false, - "payFeeFromPublicL2": false, - "portalContractAddress": EthAddress { - "buffer": { + "hash": Fr { + "asBigInt": 0n, + "asBuffer": { "data": [ 0, 0, @@ -80986,11 +82777,23 @@ KernelCircuitPublicInputsFinal { 0, 0, 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, }, - "vkHash": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -81031,8 +82834,6 @@ KernelCircuitPublicInputsFinal { }, }, }, - ], - "privateCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -82253,90 +84054,134 @@ KernelCircuitPublicInputsFinal { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, + ], + "unencryptedLogPreimagesLength": Fr { + "asBigInt": 4n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 4, + ], + "type": "Buffer", + }, + }, + "unencryptedLogsHash": [ + Fr { + "asBigInt": 38042960891247304977978366569914796636n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 28, + 158, + 206, + 201, + 14, + 40, + 210, + 70, + 22, + 80, + 65, + 134, + 53, + 135, + 138, + 92, + ], + "type": "Buffer", }, - "callerContractAddress": AztecAddress { + }, + Fr { + "asBigInt": 193925133628253903808777040905688936722n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 145, + 228, + 159, + 71, + 88, + 110, + 207, + 117, + 242, + 176, + 203, + 185, + 78, + 137, + 113, + 18, + ], + "type": "Buffer", + }, + }, + ], + }, + "endMeta": AccumulatedMetaData { + "newCommitments": [ + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82376,7 +84221,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82416,7 +84261,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82456,7 +84303,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82497,90 +84344,8 @@ KernelCircuitPublicInputsFinal { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82620,7 +84385,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82660,7 +84425,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82700,7 +84467,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82741,90 +84508,8 @@ KernelCircuitPublicInputsFinal { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82864,7 +84549,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82904,7 +84589,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82944,7 +84631,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -82984,93 +84671,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - ], - "publicCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83110,7 +84713,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83150,7 +84753,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83190,7 +84795,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83231,90 +84836,10 @@ KernelCircuitPublicInputsFinal { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + ], + "newNullifiers": [ + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83354,7 +84879,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83394,7 +84919,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83434,7 +84959,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83474,91 +85001,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83598,7 +85041,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83638,7 +85081,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83678,7 +85123,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83718,91 +85163,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83842,7 +85203,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83882,7 +85245,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83922,7 +85285,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -83963,90 +85326,8 @@ KernelCircuitPublicInputsFinal { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84086,7 +85367,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84126,7 +85407,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84166,7 +85447,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84206,91 +85489,47 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84330,7 +85569,9 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffectLinkedToNoteHash { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84370,7 +85611,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "hash": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84410,7 +85651,7 @@ KernelCircuitPublicInputsFinal { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -84451,6 +85692,130 @@ KernelCircuitPublicInputsFinal { }, }, }, + SideEffectLinkedToNoteHash { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "publicCallStack": [ CallRequest { "callerContext": CallerContext { "msgSender": AztecAddress { @@ -84940,129 +86305,47 @@ KernelCircuitPublicInputsFinal { }, }, ], - "unencryptedLogPreimagesLength": Fr { - "asBigInt": 4n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 4, - ], - "type": "Buffer", - }, - }, - "unencryptedLogsHash": [ - Fr { - "asBigInt": 38042960891247304977978366569914796636n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 28, - 158, - 206, - 201, - 14, - 40, - 210, - 70, - 22, - 80, - 65, - 134, - 53, - 135, - 138, - 92, - ], - "type": "Buffer", - }, - }, - Fr { - "asBigInt": 193925133628253903808777040905688936722n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 145, - 228, - 159, - 71, - 88, - 110, - 207, - 117, - 242, - 176, - 203, - 185, - 78, - 137, - 113, - 18, - ], - "type": "Buffer", - }, - }, - ], }, "isPrivate": true, + "metaHwm": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, } `; diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr index c19d515803f..49c833d37a8 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr @@ -127,7 +127,6 @@ pub fn initialize_end_values( public_inputs.end.encrypted_log_preimages_length = start.encrypted_log_preimages_length; public_inputs.end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; - public_inputs.end.optionally_revealed_data = start.optionally_revealed_data; public_inputs.end.new_contracts = array_to_bounded_vec(start.new_contracts); } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr index 3fe0658498d..af196b22e5d 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr @@ -107,10 +107,10 @@ impl PrivateKernelInputsInit { self.tx_request.function_data); // TODO(David): What previous kernel proof are we talking about, since this is private-kernel-init - let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.end.aggregation_object,self.private_call.proof); + let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object,self.private_call.proof); assert(is_previous_state_valid); - public_inputs.end.aggregation_object = updated_aggregation_object; + public_inputs.aggregation_object = updated_aggregation_object; public_inputs.finish() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr index b8f7a7fe114..b35a28e90c9 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -68,10 +68,10 @@ impl PrivateKernelInputsInner { this_call_stack_item.public_inputs.contract_deployment_data, this_call_stack_item.function_data); - let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.end.aggregation_object,self.private_call.proof); + let (is_previous_state_valid, updated_aggregation_object) = verify_previous_kernel_state(public_inputs.aggregation_object,self.private_call.proof); assert(is_previous_state_valid); - public_inputs.end.aggregation_object = updated_aggregation_object; + public_inputs.aggregation_object = updated_aggregation_object; public_inputs.finish() } diff --git a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr index 6c6496b7ad5..0e20322fb03 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_ordering.nr @@ -10,7 +10,7 @@ use dep::types::{ nullifier_key_validation_request::NullifierKeyValidationRequestContext, previous_kernel_data::PreviousKernelData, kernel_circuit_public_inputs::{ - KernelCircuitPublicInputsBuilder, + KernelCircuitPublicInputsBuilder, KernelCircuitPublicInputsFinal, }, side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered}, @@ -20,6 +20,8 @@ use dep::types::{ MAX_NEW_NULLIFIERS_PER_TX, MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, hash::{ @@ -45,7 +47,7 @@ struct PrivateKernelInputsOrdering { impl PrivateKernelInputsOrdering { fn validate_inputs(self) { - assert_eq(array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, + assert_eq(array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, "Private call stack must be empty when executing the ordering circuit"); } @@ -200,7 +202,7 @@ impl PrivateKernelInputsOrdering { self.validate_inputs(); common::validate_previous_kernel_values(self.previous_kernel.public_inputs.end); - + // Do this before any functions can modify the inputs. common::initialize_end_values(self.previous_kernel, &mut public_inputs); @@ -210,9 +212,10 @@ impl PrivateKernelInputsOrdering { self.match_reads_to_commitments(&mut public_inputs); - self.match_nullifiers_to_commitments_and_squash(&mut public_inputs); + self.match_nullifiers_to_commitments_and_squash(&mut public_inputs); + + PrivateKernelInputsOrdering::apply_commitment_nonces(&mut public_inputs); - PrivateKernelInputsOrdering::apply_commitment_nonces(&mut public_inputs); public_inputs.to_final() } @@ -266,7 +269,7 @@ mod tests { self.compute_unique_siloed_commitments(self.previous_kernel.end.new_commitments.storage) } - // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed + // A helper function that uses the first nullifer in the previous kernel to compute the unique siloed // commitments for the given commitments. pub fn compute_unique_siloed_commitments(self, commitments: [SideEffect; N]) -> [SideEffect; N] { let first_nullifier = self.previous_kernel.end.new_nullifiers.get_unchecked(0); diff --git a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr index 87929586626..7bb3a644a2c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr @@ -1,7 +1,7 @@ use dep::types::{ abis::{ call_request::CallRequest, - call_stack_item::PublicCallStackItem, + public_call_stack_item::PublicCallStackItem, combined_accumulated_data::{CombinedAccumulatedData, CombinedAccumulatedDataBuilder}, kernel_circuit_public_inputs::KernelCircuitPublicInputsBuilder, new_contract_data::NewContractData, @@ -71,8 +71,6 @@ pub fn initialize_end_values( circuit_outputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); circuit_outputs.end.new_l2_to_l1_msgs = array_to_bounded_vec(start.new_l2_to_l1_msgs); - circuit_outputs.end.optionally_revealed_data = start.optionally_revealed_data; - circuit_outputs.end.public_data_update_requests = array_to_bounded_vec(start.public_data_update_requests); circuit_outputs.end.public_data_reads = array_to_bounded_vec(start.public_data_reads); diff --git a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr index 5eb17a9f097..3181b8cdbd2 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -293,6 +293,7 @@ impl BaseRollupInputs { let new_contracts = kernel_data.public_inputs.end.new_contracts; calldata_hash_inputs[offset] = new_contracts[0].contract_address.to_field(); + // TODO(#3938): make portal address 20 bytes here when updating the hashing calldata_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address.to_field(); offset += MAX_NEW_CONTRACTS_PER_TX * 2; @@ -355,7 +356,7 @@ impl BaseRollupInputs { // TODO(Kev): This aggregate_proof method is duplicated in a lot of places fn aggregate_proofs(self) -> AggregationObject { // TODO: for now we simply return the aggregation object from the first proof - self.kernel_data.public_inputs.end.aggregation_object + self.kernel_data.public_inputs.aggregation_object } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr index 47605e17f6c..52e256d2ea3 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis.nr @@ -16,7 +16,6 @@ mod combined_constant_data; mod nullifier_key_validation_request; mod public_data_read; mod public_data_update_request; -mod optionally_revealed_data; mod combined_accumulated_data; @@ -25,7 +24,8 @@ mod kernel_circuit_public_inputs; mod previous_kernel_data; mod call_request; -mod call_stack_item; +mod private_call_stack_item; +mod public_call_stack_item; mod call_context; mod public_call_data; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr index 42e51622655..e6c3189b487 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr @@ -12,7 +12,6 @@ use crate::{ Serialize, }, }; -use dep::std::cmp::Eq; // docs:start:call-context struct CallContext { @@ -95,9 +94,11 @@ impl Deserialize for CallContext { } #[test] -fn serialization_smoke() { +fn serialization_of_empty() { let context: CallContext = dep::std::unsafe::zeroed(); - let _serialized = context.serialize(); + let serialized = context.serialize(); + let deserialized = CallContext::deserialize(serialized); + assert(context.eq(deserialized)); } #[test] diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr index 9e74c0ae103..59269896760 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/combined_accumulated_data.nr @@ -3,12 +3,10 @@ use crate::{ call_request::CallRequest, new_contract_data::NewContractData, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - optionally_revealed_data::OptionallyRevealedData, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, - }, - mocked::AggregationObject + } }; use crate::constants::{ MAX_READ_REQUESTS_PER_TX, @@ -19,15 +17,16 @@ use crate::constants::{ MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, + + MAX_NEW_COMMITMENTS_PER_TX_META, + MAX_NEW_NULLIFIERS_PER_TX_META, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, }; struct CombinedAccumulatedData { - aggregation_object: AggregationObject, - read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], @@ -48,16 +47,12 @@ struct CombinedAccumulatedData { new_contracts: [NewContractData; MAX_NEW_CONTRACTS_PER_TX], - optionally_revealed_data: [OptionallyRevealedData; MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX], - public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } struct FinalAccumulatedData { - aggregation_object: AggregationObject, - new_commitments: [SideEffect; MAX_NEW_COMMITMENTS_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], @@ -74,12 +69,15 @@ struct FinalAccumulatedData { unencrypted_log_preimages_length: Field, new_contracts: [NewContractData; MAX_NEW_CONTRACTS_PER_TX], - optionally_revealed_data: [OptionallyRevealedData; MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX] } -struct CombinedAccumulatedDataBuilder { - aggregation_object: AggregationObject, +struct AccumulatedMetaData { + new_commitments: [SideEffect; MAX_NEW_COMMITMENTS_PER_TX_META], + new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX_META], + public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META], +} +struct CombinedAccumulatedDataBuilder { read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -100,8 +98,6 @@ struct CombinedAccumulatedDataBuilder { new_contracts: BoundedVec, - optionally_revealed_data: [OptionallyRevealedData; MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX], - public_data_update_requests: BoundedVec, public_data_reads: BoundedVec, @@ -110,7 +106,6 @@ struct CombinedAccumulatedDataBuilder { impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - aggregation_object: self.aggregation_object, read_requests: self.read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, @@ -130,13 +125,11 @@ impl CombinedAccumulatedDataBuilder { new_contracts: self.new_contracts.storage, - optionally_revealed_data: self.optionally_revealed_data, - public_data_update_requests: self.public_data_update_requests.storage, public_data_reads: self.public_data_reads.storage, } - } + } pub fn to_final(self) -> FinalAccumulatedData { assert_eq(self.read_requests.len, 0, "Final accumulated data: read requests not empty"); @@ -145,7 +138,6 @@ impl CombinedAccumulatedDataBuilder { assert_eq(self.public_data_reads.len, 0, "Final accumulated data: public data reads not empty"); FinalAccumulatedData { - aggregation_object: self.aggregation_object, new_commitments: self.new_commitments.storage, new_nullifiers: self.new_nullifiers.storage, @@ -161,7 +153,22 @@ impl CombinedAccumulatedDataBuilder { unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, new_contracts: self.new_contracts.storage, - optionally_revealed_data: self.optionally_revealed_data, } - } + } +} + +struct AccumulatedMetaDataBuilder { + new_commitments: BoundedVec, + new_nullifiers: BoundedVec, + public_call_stack: BoundedVec, +} + +impl AccumulatedMetaDataBuilder { + pub fn finish(self) -> AccumulatedMetaData { + AccumulatedMetaData { + new_commitments: self.new_commitments.storage, + new_nullifiers: self.new_nullifiers.storage, + public_call_stack: self.public_call_stack.storage, + } + } } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr index 513c90e7d1f..29c193a47dc 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr @@ -21,9 +21,12 @@ struct FunctionData { is_constructor : bool, } -impl Hash for FunctionData { - fn hash(self) -> Field { - pedersen_hash(self.serialize(), GENERATOR_INDEX__FUNCTION_DATA) +impl Eq for FunctionData { + fn eq(self, other: Self) -> bool { + self.selector.eq(other.selector) & + self.is_internal == other.is_internal & + self.is_private == other.is_private & + self.is_constructor == other.is_constructor } } @@ -51,3 +54,26 @@ impl Deserialize for FunctionData { } } } + +impl Hash for FunctionData { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__FUNCTION_DATA) + } +} + +#[test] +fn serialization_of_empty() { + let data: FunctionData = dep::std::unsafe::zeroed(); + let serialized = data.serialize(); + let deserialized = FunctionData::deserialize(serialized); + assert(data.eq(deserialized)); +} + +#[test] +fn empty_hash() { + let data: FunctionData = dep::std::unsafe::zeroed(); + let hash = data.hash(); + + // Value from function_data.test.ts "computes empty item hash" test + assert_eq(hash, 0x200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d); +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr index 42358630586..81c040a246b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr @@ -1,5 +1,9 @@ use dep::std::cmp::Eq; use crate::{ + address::{ + AztecAddress, + EthAddress, + }, constants::{ GENERATOR_INDEX__GLOBAL_VARIABLES, GLOBAL_VARIABLES_LENGTH, @@ -12,12 +16,16 @@ use crate::{ }, }; +// docs:start:global-variables struct GlobalVariables { chain_id : Field, version : Field, block_number : Field, timestamp : Field, + coinbase : EthAddress, + fee_recipient : AztecAddress, } +// docs:end:global-variables impl Serialize for GlobalVariables { fn serialize(self) -> [Field; GLOBAL_VARIABLES_LENGTH] { @@ -25,7 +33,9 @@ impl Serialize for GlobalVariables { self.chain_id, self.version, self.block_number, - self.timestamp + self.timestamp, + self.coinbase.to_field(), + self.fee_recipient.to_field(), ] } } @@ -37,6 +47,8 @@ impl Deserialize for GlobalVariables { version: serialized[1], block_number: serialized[2], timestamp: serialized[3], + coinbase: EthAddress::from_field(serialized[4]), + fee_recipient: AztecAddress::from_field(serialized[5]), } } } @@ -46,7 +58,9 @@ impl Eq for GlobalVariables { (self.chain_id == other.chain_id) & (self.version == other.version) & (self.block_number == other.block_number) & - (self.timestamp == other.timestamp) + (self.timestamp == other.timestamp) & + (self.coinbase == other.coinbase) & + (self.fee_recipient == other.fee_recipient) } } @@ -57,12 +71,14 @@ impl Empty for GlobalVariables { version: 0, block_number: 0, timestamp: 0, + coinbase: EthAddress::empty(), + fee_recipient: AztecAddress::empty(), } } } #[test] -fn serialization_deserialization_smoke() { +fn serialization_of_empty() { let vars: GlobalVariables = dep::std::unsafe::zeroed(); let _serialized = vars.serialize(); let _deserialized = GlobalVariables::deserialize(_serialized); diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr index c847b901b36..22e8a41c497 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr @@ -2,24 +2,36 @@ use crate::abis::{ combined_accumulated_data::{ CombinedAccumulatedData, FinalAccumulatedData, + AccumulatedMetaData, + AccumulatedMetaDataBuilder, CombinedAccumulatedDataBuilder, }, - combined_constant_data::CombinedConstantData, + combined_constant_data::CombinedConstantData }; +use crate::mocked::AggregationObject; struct KernelCircuitPublicInputs { + aggregation_object: AggregationObject, + meta_hwm: Field, end: CombinedAccumulatedData, constants: CombinedConstantData, is_private: bool, } struct KernelCircuitPublicInputsFinal { + aggregation_object: AggregationObject, + meta_hwm: Field, + end_meta: AccumulatedMetaData, + // TODO(fees) change this to end_app_logic end: FinalAccumulatedData, constants: CombinedConstantData, is_private: bool, } struct KernelCircuitPublicInputsBuilder { + aggregation_object: AggregationObject, + meta_hwm: Field, + end_meta: AccumulatedMetaDataBuilder, end: CombinedAccumulatedDataBuilder, constants: CombinedConstantData, is_private: bool, @@ -28,6 +40,8 @@ struct KernelCircuitPublicInputsBuilder { impl KernelCircuitPublicInputsBuilder { pub fn finish(self) -> KernelCircuitPublicInputs { KernelCircuitPublicInputs { + aggregation_object: self.aggregation_object, + meta_hwm: self.meta_hwm, end: self.end.finish(), constants: self.constants, is_private: self.is_private, @@ -35,8 +49,13 @@ impl KernelCircuitPublicInputsBuilder { } pub fn to_final(self) -> KernelCircuitPublicInputsFinal { + let meta = self.end_meta.finish(); + let app = self.end.to_final(); KernelCircuitPublicInputsFinal { - end: self.end.to_final(), + aggregation_object: self.aggregation_object, + meta_hwm: self.meta_hwm, + end_meta: meta, + end: app, constants: self.constants, is_private: self.is_private, } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/optionally_revealed_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/optionally_revealed_data.nr deleted file mode 100644 index b4808f120b8..00000000000 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/optionally_revealed_data.nr +++ /dev/null @@ -1,13 +0,0 @@ -use crate::abis::function_data::FunctionData; -use crate::address::EthAddress; - -struct OptionallyRevealedData { - call_stack_item_hash : Field, - function_data : FunctionData, - vk_hash : Field, - portal_contract_address : EthAddress, - pay_fee_from_l1 : bool, - pay_fee_from_public_l2 : bool, - called_from_l1 : bool, - called_from_public_l2 : bool, -} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr new file mode 100644 index 00000000000..3ecdebed3b4 --- /dev/null +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr @@ -0,0 +1,91 @@ +use crate::{ + abis::{ + function_data::FunctionData, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + }, + address::AztecAddress, + constants::{ + GENERATOR_INDEX__CALL_STACK_ITEM, + PRIVATE_CALL_STACK_ITEM_LENGTH, + }, + hash::pedersen_hash, + traits::{ + Deserialize, + Hash, + Serialize, + }, + utils::reader::Reader, +}; + +struct PrivateCallStackItem { + // This is the _actual_ contract address relating to where this function's code resides in the + // contract tree. Regardless of whether this is a call or delegatecall, this + // `contract_address` _does not change_. Amongst other things, it's used as a lookup for + // getting the correct code from the tree. There is a separate `storage_contract_address` + // within a CallStackItem which varies depending on whether this is a call or delegatecall. + contract_address: AztecAddress, + function_data: FunctionData, + public_inputs: PrivateCircuitPublicInputs, +} + +impl Eq for PrivateCallStackItem { + fn eq(self, other: Self) -> bool { + self.contract_address.eq(other.contract_address) & + self.function_data.eq(other.function_data) & + self.public_inputs.eq(other.public_inputs) + } +} + +impl Serialize for PrivateCallStackItem { + fn serialize(self) -> [Field; PRIVATE_CALL_STACK_ITEM_LENGTH] { + let mut fields: BoundedVec = BoundedVec::new(0); + + fields.push(self.contract_address.to_field()); + fields.extend_from_array(self.function_data.serialize()); + fields.extend_from_array(self.public_inputs.serialize()); + + assert_eq(fields.len(), PRIVATE_CALL_STACK_ITEM_LENGTH); + + fields.storage + } +} + +impl Deserialize for PrivateCallStackItem { + fn deserialize(serialized: [Field; PRIVATE_CALL_STACK_ITEM_LENGTH]) -> Self { + // TODO(#4390): This should accept a reader ^ to avoid copying data. + let mut reader = Reader::new(serialized); + + let item = Self { + contract_address: reader.read_struct(AztecAddress::deserialize), + function_data: reader.read_struct(FunctionData::deserialize), + public_inputs: reader.read_struct(PrivateCircuitPublicInputs::deserialize), + }; + + reader.finish(); + item + } +} + +impl Hash for PrivateCallStackItem { + fn hash(self) -> Field { + pedersen_hash(self.serialize(), GENERATOR_INDEX__CALL_STACK_ITEM) + } +} + +#[test] +fn serialization_of_empty() { + let item: PrivateCallStackItem = dep::std::unsafe::zeroed(); + let serialized = item.serialize(); + let deserialized = PrivateCallStackItem::deserialize(serialized); + assert(item.eq(deserialized)); +} + +#[test] +fn empty_hash() { + let mut item: PrivateCallStackItem = dep::std::unsafe::zeroed(); + item.function_data.is_private = true; + let hash = item.hash(); + + // Value from private_call_stack_item.test.ts "computes empty item hash" test + assert_eq(hash, 0x2442dd521c59987a4291be0fd11198e5a4d87c8bc36cf3b65c5229f61fc37b30); +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index 9995bee6a05..af410cef81c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -33,10 +33,12 @@ use crate::{ struct PrivateCircuitPublicInputs { call_context: CallContext, - + args_hash: Field, return_values: [Field; RETURN_VALUES_LENGTH], + meta_hwm: u32, + read_requests: [SideEffect; MAX_READ_REQUESTS_PER_CALL], nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], @@ -67,13 +69,39 @@ struct PrivateCircuitPublicInputs { version: Field, } +impl Eq for PrivateCircuitPublicInputs { + fn eq(self, other: Self) -> bool { + self.call_context.eq(other.call_context) & + self.args_hash.eq(other.args_hash) & + (self.return_values == other.return_values) & + (self.read_requests == other.read_requests) & + (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & + (self.new_commitments == other.new_commitments) & + (self.new_nullifiers == other.new_nullifiers) & + (self.private_call_stack_hashes == other.private_call_stack_hashes) & + (self.public_call_stack_hashes == other.public_call_stack_hashes) & + (self.new_l2_to_l1_msgs == other.new_l2_to_l1_msgs) & + (self.end_side_effect_counter == other.end_side_effect_counter) & + (self.encrypted_logs_hash == other.encrypted_logs_hash) & + (self.unencrypted_logs_hash == other.unencrypted_logs_hash) & + (self.encrypted_log_preimages_length == other.encrypted_log_preimages_length) & + (self.unencrypted_log_preimages_length == other.unencrypted_log_preimages_length) & + self.historical_header.eq(other.historical_header) & + self.contract_deployment_data.eq(other.contract_deployment_data) & + self.chain_id.eq(other.chain_id) & + self.version.eq(other.version) + } +} + impl Serialize for PrivateCircuitPublicInputs { fn serialize(self) -> [Field; PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH] { - let mut fields: BoundedVec = BoundedVec::new(0); + let mut fields: BoundedVec = BoundedVec::new(0); fields.extend_from_array(self.call_context.serialize()); fields.push(self.args_hash); fields.extend_from_array(self.return_values); + fields.push(self.meta_hwm as Field); + for i in 0..MAX_READ_REQUESTS_PER_CALL{ fields.extend_from_array(self.read_requests[i].serialize()); } @@ -113,6 +141,7 @@ impl Deserialize for PrivateCircuitPublicI call_context: reader.read_struct(CallContext::deserialize), args_hash: reader.read(), return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), + meta_hwm: reader.read() as u32, read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), new_commitments: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_COMMITMENTS_PER_CALL]), @@ -143,13 +172,18 @@ impl Hash for PrivateCircuitPublicInputs { } #[test] -fn serialization_smoke() { +fn serialization_of_empty() { let pcpi: PrivateCircuitPublicInputs = dep::std::unsafe::zeroed(); - let _serialized = pcpi.serialize(); + let serialized = pcpi.serialize(); + let deserialized = PrivateCircuitPublicInputs::deserialize(serialized); + assert(pcpi.eq(deserialized)); } #[test] -fn hash_smoke() { - let pcpi: PrivateCircuitPublicInputs = dep::std::unsafe::zeroed(); - let _hashed = pcpi.hash(); +fn empty_hash() { + let inputs: PrivateCircuitPublicInputs = dep::std::unsafe::zeroed(); + let hash = inputs.hash(); + + // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test + assert_eq(hash, 0x1304e6c42e3c53fc7c918cbf1ea70333b4f214726c0784cf9878cd641967dab1); } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr index fb7bde97e68..b0365bbdb40 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,6 +1,6 @@ use crate::abis::{ call_request::CallRequest, - call_stack_item::PrivateCallStackItem, + private_call_stack_item::PrivateCallStackItem, membership_witness::{ ContractLeafMembershipWitness, FunctionLeafMembershipWitness, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr index bc59e74e109..fc57026db5b 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ call_request::CallRequest, - call_stack_item::PublicCallStackItem, + public_call_stack_item::PublicCallStackItem, }, address::EthAddress, mocked::Proof, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_stack_item.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr similarity index 58% rename from yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_stack_item.nr rename to yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr index 45ebceaf010..879b5e7d768 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/call_stack_item.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr @@ -1,37 +1,11 @@ use crate::abis::{ function_data::FunctionData, - private_circuit_public_inputs::PrivateCircuitPublicInputs, public_circuit_public_inputs::PublicCircuitPublicInputs, }; use crate::address::AztecAddress; -use crate::constants::{ - GENERATOR_INDEX__CALL_STACK_ITEM, -}; +use crate::constants::GENERATOR_INDEX__CALL_STACK_ITEM; use crate::traits::Hash; -struct PrivateCallStackItem { - // This is the _actual_ contract address relating to where this function's code resides in the - // contract tree. Regardless of whether this is a call or delegatecall, this - // `contract_address` _does not change_. Amongst other things, it's used as a lookup for - // getting the correct code from the tree. There is a separate `storage_contract_address` - // within a CallStackItem which varies depending on whether this is a call or delegatecall. - contract_address: AztecAddress, - public_inputs: PrivateCircuitPublicInputs, - function_data: FunctionData, - // Not really needed for PrivateCallStackItem. - is_execution_request: bool, -} - -impl Hash for PrivateCallStackItem { - fn hash(self) -> Field { - dep::std::hash::pedersen_hash_with_separator([ - self.contract_address.to_field(), - self.function_data.hash(), - self.public_inputs.hash(), - ], GENERATOR_INDEX__CALL_STACK_ITEM) - } -} - struct PublicCallStackItem { contract_address: AztecAddress, public_inputs: PublicCircuitPublicInputs, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr index 8d981d4ca12..372aefde016 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr @@ -58,6 +58,12 @@ struct PublicCircuitPublicInputs{ prover_address: AztecAddress, } +impl Eq for PublicCircuitPublicInputs { + fn eq(self, other: Self) -> bool { + self.serialize() == other.serialize() + } +} + impl Serialize for PublicCircuitPublicInputs { fn serialize(self) -> [Field; PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH] { let mut fields: BoundedVec = BoundedVec::new(0); @@ -119,9 +125,11 @@ impl Hash for PublicCircuitPublicInputs { } #[test] -fn serialization_smoke() { +fn serialization_of_empty() { let pcpi: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); - let _serialized = pcpi.serialize(); + let serialized = pcpi.serialize(); + let deserialized = PublicCircuitPublicInputs::deserialize(serialized); + assert(pcpi.eq(deserialized)); } #[test] diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr index 33e56273756..d4dc79fd9bf 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/address.nr @@ -248,6 +248,18 @@ impl ToField for PublicKeysHash { } } +impl Serialize<1> for PublicKeysHash { + fn serialize(self: Self) -> [Field; 1] { + [self.to_field()] + } +} + +impl Deserialize<1> for PublicKeysHash { + fn deserialize(fields: [Field; 1]) -> Self { + PublicKeysHash::from_field(fields[0]) + } +} + impl PublicKeysHash { pub fn from_field(field : Field) -> Self { Self { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr index df1892736a2..52d787e528c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/constants.nr @@ -42,11 +42,14 @@ global MAX_NEW_L2_TO_L1_MSGS_PER_TX: Field = 2; global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: Field = 16; global MAX_PUBLIC_DATA_READS_PER_TX: Field = 16; global MAX_NEW_CONTRACTS_PER_TX: Field = 1; -global MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX: Field = 4; global MAX_READ_REQUESTS_PER_TX: Field = 128; global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX: Field = 4; global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1; + +global MAX_NEW_COMMITMENTS_PER_TX_META: Field = 8; +global MAX_NEW_NULLIFIERS_PER_TX_META: Field = 8; +global MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META: Field = 2; // docs:end:constants // ROLLUP CONTRACT CONSTANTS - constants used only in l1-contracts @@ -61,6 +64,7 @@ global PUBLIC_DATA_TREE_HEIGHT: Field = 40; global NULLIFIER_TREE_HEIGHT: Field = 20; global L1_TO_L2_MSG_TREE_HEIGHT: Field = 16; global ROLLUP_VK_TREE_HEIGHT: Field = 8; +global ARTIFACT_FUNCTION_TREE_MAX_HEIGHT = 5; // SUB-TREES RELATED CONSTANTS global CONTRACT_SUBTREE_HEIGHT: Field = 0; @@ -81,7 +85,31 @@ global MAPPING_SLOT_PEDERSEN_SEPARATOR: Field = 4; // sha256 hash is stored in two fields to accommodate all 256-bits of the hash global NUM_FIELDS_PER_SHA256: Field = 2; global ARGS_HASH_CHUNK_LENGTH: u32 = 32; -global ARGS_HASH_CHUNK_COUNT: u32 = 16; +global ARGS_HASH_CHUNK_COUNT: u32 = 32; + +// CONTRACT CLASS CONSTANTS +// This should be around 8192 (assuming 2**15 instructions packed at 8 bytes each), +// but it's reduced to speed up build times, otherwise the ClassRegisterer takes over 5 mins to compile. +// We are not using 1024 so we can squeeze in a few more args to methods that consume packed public bytecode, +// such as the ClassRegisterer.register, and still land below the 32 * 32 max args limit for hashing. +global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: Field = 1000; +// Bytecode size for private functions is per function, not for the entire contract. +// Note that private functions bytecode includes a mix of acir and brillig. +global MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS: Field = 500; +// Same for unconstrained functions: the size is per function. +global MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS: Field = 500; +// Since we are not yet emitting selectors we'll use this magic value to identify events emitted by the ClassRegisterer. +// This is just a stopgap until we implement proper selectors. +// sha224sum 'struct ContractClassRegistered {contract_class_id: ContractClassId, version: Field, artifact_hash: Field, private_functions_root: Field, packed_public_bytecode: [Field; MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS] }' +global REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = 0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8; +// sha224sum 'struct ClassPrivateFunctionBroadcasted' +global REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = 0x1b70e95fde0b70adc30496b90a327af6a5e383e028e7a43211a07bcd; +// sha224sum 'struct ClassUnconstrainedFunctionBroadcasted' +global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99; + +// CONTRACT INSTANCE CONSTANTS +// sha224sum 'struct ContractInstanceDeployed' +global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; // NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts // Some are defined here because Noir doesn't yet support globals referencing other globals yet. @@ -98,22 +126,22 @@ global MAX_NOTES_PER_PAGE: Field = 10; // VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2; global VIEW_NOTE_ORACLE_RETURN_LENGTH: Field = 212; global CALL_CONTEXT_LENGTH: Field = 8; -global GLOBAL_VARIABLES_LENGTH: Field = 4; +global GLOBAL_VARIABLES_LENGTH: Field = 6; global PARTIAL_STATE_REFERENCE_LENGTH: Field = 8; global STATE_REFERENCE_LENGTH: Field = 10; // 2 for snap + 8 for partial -global HEADER_LENGTH: Field = 18; // 2 for last_archive, 2 for body hash, 10 for state reference, 4 for global vars +global HEADER_LENGTH: Field = 20; // 2 for last_archive, 2 for body hash, 10 for state reference, 6 for global vars global FUNCTION_DATA_LENGTH: Field = 4; global CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6; // Change this ONLY if you have changed the PrivateCircuitPublicInputs structure. // In other words, if the structure/size of the public inputs of a function call changes then we should change this -// constant as well CALL_PRIVATE_FUNCTION_RETURN_SIZE -global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 204; +// constant as well PRIVATE_CALL_STACK_ITEM_LENGTH +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 207; +global PRIVATE_CALL_STACK_ITEM_LENGTH: Field = 212; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 3; global CONTRACT_STORAGE_READ_LENGTH: Field = 2; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. -global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 201; +global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 203; global GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674; -global CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 210; global COMMITMENTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; global NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; global PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: Field = 1024; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr index c7637c795bb..668234a8832 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/contrakt/deployment_data.nr @@ -24,6 +24,16 @@ struct ContractDeploymentData { } // docs:end:contract-deployment-data +impl Eq for ContractDeploymentData { + fn eq(self, other: Self) -> bool { + self.public_key.eq(other.public_key) & + self.initialization_hash.eq(other.initialization_hash) & + self.contract_class_id.eq(other.contract_class_id) & + self.contract_address_salt.eq(other.contract_address_salt) & + self.portal_contract_address.eq(other.portal_contract_address) + } +} + impl Hash for ContractDeploymentData { fn hash(self) -> Field { pedersen_hash(self.serialize(), GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA) @@ -67,3 +77,11 @@ impl ContractDeploymentData { self.portal_contract_address.assert_is_zero(); } } + +#[test] +fn serialization_of_empty() { + let data: ContractDeploymentData = dep::std::unsafe::zeroed(); + let serialized = data.serialize(); + let deserialized = ContractDeploymentData::deserialize(serialized); + assert(data.eq(deserialized)); +} diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr index c67a3c03e38..f5f38bceb4c 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/header.nr @@ -37,6 +37,15 @@ struct Header { } // docs:end:header +impl Eq for Header { + fn eq(self, other: Self) -> bool { + self.last_archive.eq(other.last_archive) & + (self.body_hash == other.body_hash) & + self.state.eq(other.state) & + self.global_variables.eq(other.global_variables) + } +} + impl Serialize for Header { fn serialize(self) -> [Field; HEADER_LENGTH] { let mut fields: BoundedVec = BoundedVec::new(0); @@ -92,10 +101,11 @@ impl Hash for Header { } #[test] -fn serialization_deserialization_smoke() { +fn serialization_of_empty() { let header: Header = dep::std::unsafe::zeroed(); - let _serialized = header.serialize(); - let _deserialized = Header::deserialize(_serialized); + let serialized = header.serialize(); + let deserialized = Header::deserialize(serialized); + assert(header.eq(deserialized)); } #[test] diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/interop_testing.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/interop_testing.nr index e5d28d3eb48..02d54fa075d 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/interop_testing.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/interop_testing.nr @@ -6,8 +6,8 @@ use crate::abis::function_data::FunctionData; use crate::abis::function_leaf_preimage::FunctionLeafPreimage; use crate::contrakt::deployment_data::ContractDeploymentData; use crate::abis::function_selector::FunctionSelector; -use crate::hash::{compute_l2_to_l1_hash, sha256_to_field}; -use crate::abis::call_stack_item::PublicCallStackItem; +use crate::hash::{compute_l2_to_l1_hash, sha256_to_field, hash_args}; +use crate::abis::public_call_stack_item::PublicCallStackItem; use crate::abis::public_circuit_public_inputs::PublicCircuitPublicInputs; use crate::abis::side_effect::SideEffect; use crate::contract_class::ContractClassId; @@ -47,6 +47,16 @@ fn compute_address_from_partial_and_pubkey() { assert(address.to_field() == 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197); } +#[test] +fn compute_var_args_hash() { + let mut input = [0; 800]; + for i in 0..800 { + input[i] = i as Field; + } + let hash = hash_args(input); + assert(hash == 1557627899280963684159398665725097926236612957540256425197580046184563077271); +} + #[test] fn compute_tx_request_hash() { let tx_request = TxRequest { @@ -119,7 +129,7 @@ fn compute_call_stack_item_request_hash() { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: true, function_data }; // Value from abis.test.ts "Computes a callstack item request hash" test - assert_eq(call_stack_item.hash(), 0x2c36008a759d932a3a1986429aa295e2c2d4e62c33197a7d259750d29347bf30); + assert_eq(call_stack_item.hash(), 0x28cb4c264eb11e13c77a5e60b251a6b3edfb4cfed786c4f1ec5e1749fede9b78); } #[test] @@ -136,5 +146,5 @@ fn compute_call_stack_item_hash() { let call_stack_item = PublicCallStackItem { contract_address, public_inputs, is_execution_request: false, function_data }; // Value from abis.test.ts "Computes a callstack item hash" test - assert_eq(call_stack_item.hash(), 0x037cb5ba672a7c461e23cf22ae618757ab4f1a912f3fdc93b2b2800cfe57bb91); + assert_eq(call_stack_item.hash(), 0x17095bbb9e3e104dc520b6eec9338e9b6ce1fdc0f3a66b06d5ca90b15909ad0e); } diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr index 7240ffed93d..7e22fd8bee0 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr @@ -76,7 +76,7 @@ impl Empty for PartialStateReference { } #[test] -fn serialization_deserialization_smoke() { +fn serialization_of_empty() { let partial: PartialStateReference = dep::std::unsafe::zeroed(); let _serialized = partial.serialize(); let _deserialized = PartialStateReference::deserialize(_serialized); diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr index 1a064bd681b..99aa8a52d74 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/state_reference.nr @@ -68,7 +68,7 @@ impl Empty for StateReference { } #[test] -fn serialization_deserialization_smoke() { +fn serialization_of_empty() { let state: StateReference = dep::std::unsafe::zeroed(); let _serialized = state.serialize(); let _deserialized = StateReference::deserialize(_serialized); diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr index 6fef627310d..32b29b89d48 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr @@ -9,7 +9,10 @@ use crate::{ append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables, }, - address::AztecAddress, + address::{ + AztecAddress, + EthAddress, + }, constants::NUM_FIELDS_PER_SHA256, grumpkin_point::GrumpkinPoint, header::Header, @@ -27,6 +30,16 @@ fn empty_append_only_tree() -> AppendOnlyTreeSnapshot { AppendOnlyTreeSnapshot::zero() } +// Workaround for https://github.com/noir-lang/noir/issues/1440 +fn empty_eth_address() -> EthAddress { + EthAddress::empty() +} + +// Workaround for https://github.com/noir-lang/noir/issues/1440 +fn empty_aztec_address() -> AztecAddress { + AztecAddress::empty() +} + global HEADER = Header { last_archive: empty_append_only_tree(), body_hash: [0; NUM_FIELDS_PER_SHA256], @@ -49,6 +62,8 @@ global HEADER = Header { chain_id: 0, version: 0, block_number: 0, - timestamp: 0 + timestamp: 0, + coinbase: empty_eth_address(), + fee_recipient: empty_aztec_address(), } }; diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/previous_kernel_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/previous_kernel_data_builder.nr index 5bfa665a5de..2f4159fdc5a 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/previous_kernel_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/previous_kernel_data_builder.nr @@ -12,7 +12,7 @@ use crate::{ }, address::{AztecAddress, EthAddress}, header::Header, - mocked::{Proof, VerificationKey}, + mocked::{AggregationObject, Proof, VerificationKey}, tests::{ fixtures, testing_harness::build_tx_context, @@ -190,6 +190,8 @@ impl PreviousKernelDataBuilder { pub fn finish(self) -> PreviousKernelData { let public_inputs = KernelCircuitPublicInputs { + aggregation_object: AggregationObject {}, + meta_hwm: 0, end: self.end.finish(), constants: CombinedConstantData { historical_header: self.historical_header, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr index 4bfa514397a..64f17d36727 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ call_request::{CallerContext, CallRequest}, - call_stack_item::PrivateCallStackItem, + private_call_stack_item::PrivateCallStackItem, function_data::FunctionData, membership_witness::{ ContractLeafMembershipWitness, @@ -188,9 +188,8 @@ impl PrivateCallDataBuilder { pub fn get_call_stack_item_hash(self) -> Field { let call_stack_item = PrivateCallStackItem { contract_address: self.contract_address, - public_inputs: self.public_inputs.finish(), - is_execution_request: false, function_data: self.function_data, + public_inputs: self.public_inputs.finish(), }; call_stack_item.hash() } @@ -198,9 +197,8 @@ impl PrivateCallDataBuilder { pub fn finish(self) -> PrivateCallData { let call_stack_item = PrivateCallStackItem { contract_address: self.contract_address, - public_inputs: self.public_inputs.finish(), - is_execution_request: false, function_data: self.function_data, + public_inputs: self.public_inputs.finish(), }; PrivateCallData { diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 46196b43b4a..11c7c39842f 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -28,10 +28,12 @@ use crate::constants::{ struct PrivateCircuitPublicInputsBuilder { call_context: CallContext, - + args_hash: Field, return_values: BoundedVec, + meta_hwm: u32, + read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -113,6 +115,7 @@ impl PrivateCircuitPublicInputsBuilder { call_context: self.call_context, args_hash: self.args_hash, return_values: self.return_values.storage, + meta_hwm: self.meta_hwm, read_requests: self.read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, diff --git a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr index 48dd0bb62e1..77f9c6164cb 100644 --- a/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr +++ b/yarn-project/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr @@ -2,9 +2,9 @@ use crate::{ abis::{ call_context::CallContext, call_request::{CallerContext, CallRequest}, - call_stack_item::PublicCallStackItem, function_data::FunctionData, public_call_data::PublicCallData, + public_call_stack_item::PublicCallStackItem, public_circuit_public_inputs::PublicCircuitPublicInputs, }, address::{AztecAddress, EthAddress}, diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex index cb967fb7418..3e6eb1d27c7 100644 --- a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-init.hex @@ -1 +1 @@ -1c1d34487db43700811410f1123e682c52e2c1567e0322647cfea3826e0d5ec2af9f8c4400010122ba0d1e94a5cd2b14cf11d03fddd226f5c55b6a8cc7bded2eb5e2d0f0162e6e0000011ade16c0a93966ebd5d022b084874443007fc6834d8db2094d974a604490ebe123ef56e8a650a17d8ba4b5f38562cebb89de0dee06800d29d4a37095b9f690de275269600f0f2ea6f3b92e16eed77f829447c3e26dedf0da785ada854cef7a2a0000665a22f6bde0a5a80c7acb02d4acb772dbfe4e117eb142653d46b4b25b05287545bf11d1995f3010eaeffd8c07a749e105ddf3081d73424a48b41f7a8d8a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000011c1d34487db43700811410f1123e682c52e2c1567e0322647cfea3826e0d5ec2af9f8c4400010100000000000000000000000000000000000000000000000000000000000000001c1d34487db43700811410f1123e682c52e2c1567e0322647cfea3826e0d5ec20000000000000000000000000000000000000000000000000000000000000000af9f8c440000010000000222ba0d1e94a5cd2b14cf11d03fddd226f5c55b6a8cc7bded2eb5e2d0f0162e6e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e411248bd419dd83077a0bc5175eee27dceabf57463563520dbb95a21bc8a8000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000bfd1d9d47c3cc77755cebe96fb3e704f000000000000000000000000000000002e2bfcc4456c15bbbd60a5c50ab74b6200000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000f8000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ade16c0a93966ebd5d022b084874443007fc6834d8db2094d974a604490ebe123ef56e8a650a17d8ba4b5f38562cebb89de0dee06800d29d4a37095b9f690de275269600f0f2ea6f3b92e16eed77f829447c3e26dedf0da785ada854cef7a2a0000665a22f6bde0a5a80c7acb02d4acb772dbfe4e117eb142653d46b4b25b05287545bf11d1995f3010eaeffd8c07a749e105ddf3081d73424a48b41f7a8d8a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f091afbe4f19984434cf433711d5d7f405e567a9de76390eb8ba7139325b39542221f8a7714359b6db9baddee936a57af86dea0c27db5d107950dc2cbb852b85112d5eb07d23ba50dd7e2142f2eaea4283052deec53401f3c8fa77bdfe848257e30361feea4f3ab6445b7e977b1e9c8270bffd04b73b8c8752c4132309701df9600000000000000000000000000000000000000000000000000000000000000010aa9f47e5c69d21b78461a62b4013fd65fbebbc432d73418c00d9ab6c9eca3b01fd163e98c3058b28c0c78a7cea427a8d86699c79c4cf9eeeeca2dc63288c0850bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +040cc2d6a57a9ed70de05ba838f36237b0fd89a4454bd5769cfcb70ab5ec0fb3af9f8c4400010121b1c1ca29347a3254124b9216286785fdd33dace59259171c4089d9ffbdbd270000012e6c276e1ef4755f6fda143424585d7ddb8018de978b1afc956ee1796ae53dca0dd6412b0443036d4c7c9a65dd938a1f2fb6a2fdda1b71629299a60054082cac0e97cbc43795084338d12e0a1897f712ee9ab5b6cc96387aaf1100daab06b3792cec24fdcf1a1fd1e97fffe8c3327b22810b1aa820710e44ae757aa5561aea5712e3d6beb3b820ec5fb1f101423c55c8f5567eb26a8cfc9e987dc6ab664307a600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001040cc2d6a57a9ed70de05ba838f36237b0fd89a4454bd5769cfcb70ab5ec0fb3af9f8c440001010000000000000000000000000000000000000000000000000000000000000000040cc2d6a57a9ed70de05ba838f36237b0fd89a4454bd5769cfcb70ab5ec0fb30000000000000000000000000000000000000000af9f8c440000010000000221b1c1ca29347a3254124b9216286785fdd33dace59259171c4089d9ffbdbd270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002530185880beedb8ee97b73fd3666b376718e78beea3f78742b4294afa8b01ef000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000976da036df69fa00cec8d680da9f5a6300000000000000000000000000000000eea86c0568e1387b12350a1c0448259000000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000f8000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e6c276e1ef4755f6fda143424585d7ddb8018de978b1afc956ee1796ae53dca0dd6412b0443036d4c7c9a65dd938a1f2fb6a2fdda1b71629299a60054082cac0e97cbc43795084338d12e0a1897f712ee9ab5b6cc96387aaf1100daab06b3792cec24fdcf1a1fd1e97fffe8c3327b22810b1aa820710e44ae757aa5561aea5712e3d6beb3b820ec5fb1f101423c55c8f5567eb26a8cfc9e987dc6ab664307a600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f074b416fa89e18c29673f984f8e3d9ad17b5b0fc152870adc74c5c5801ac31f31bc721bc000c16e8575c68feb6c44f9d89a0f23e68c670ebd2d4d788ac467bfc011f21c18bcebe74fda4dc4a0fd15c50696b43f7868d41b027ab1c06743f50840ee9d7a447d0cb6a57761b930d1a293d4e5e6df49dfa23fd4dd794efc888dbc700000000000000000000000000000000000000000000000000000000000000010aa9f47e5c69d21b78461a62b4013fd65fbebbc432d73418c00d9ab6c9eca3b01fd163e98c3058b28c0c78a7cea427a8d86699c79c4cf9eeeeca2dc63288c0850bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex index eb3488ddfb9..8711bb89289 100644 --- a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-inner.hex @@ -1 +1 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002bfac660ebf33930ba9d7cb006229a4df1d39a15cd2f6c79ea782ce6f6dd12a9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d7844a21fba79cabe361f20a72d043155010a49de7fc44276d252ca34f029a72dce1ff89bbd5cd19a266b53eb7b61de1378c5080b15c2e90514438214081f3400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000269a92837d434727c58267640e2556d25c0ab4dbc88934293a508f39bc57f01000000003ca0745ba8d2296baf1a36441fb4d5ec339cde6c4a36ea2912209a110d3ca4b691864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000300423fdf46e256d15ad4e65a1c05f76bbe4600671d1adf6ade30bda500076846d000001802d4b081b972a9b85501f80a33f7b5226ba2b4be83405cc0c23dff4cb1925d171000002000fe257adc803bcc26b63f3adf82c1ae1725bc1568ea1074eff933f7747b51b24000000061ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065bcc7a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001e304753bc6d934731b298cd2a703deada24e5073b67598ace2d7a8f8a37e8cd04ecf89f82d7e9ec0c3c1445e35a49307801c3421e32714f83f9a2a9b35b252d1d15540fcbe31327bb031eb87603e01438687936367a314d2cf2b2755e9881f52040ebab1bbb02cc5fa9a358eae30abe4f94999355d23bb15802fd459f0c9ef50906bca10001002dce1ff89bbd5cd19a266b53eb7b61de1378c5080b15c2e90514438214081f342040ebab1bbb02cc5fa9a358eae30abe4f94999355d23bb15802fd459f0c9ef500000000000000000000000000000000000000000000000000000000000000000906bca1000000000000031124bf00bac5cd7fc8570fe0e40c34b8d093801a155d53e0b478d960b3a424810000000000000000000000000000000000000000000000000000000000007a6a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004269a92837d434727c58267640e2556d25c0ab4dbc88934293a508f39bc57f01000000003ca0745ba8d2296baf1a36441fb4d5ec339cde6c4a36ea2912209a110d3ca4b691864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000300423fdf46e256d15ad4e65a1c05f76bbe4600671d1adf6ade30bda500076846d000001802d4b081b972a9b85501f80a33f7b5226ba2b4be83405cc0c23dff4cb1925d171000002000fe257adc803bcc26b63f3adf82c1ae1725bc1568ea1074eff933f7747b51b24000000061ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065bcc7a90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f272a930b73bf9718dad5e0300b9d412e23419e61315c8f55b6d4722ded9e3f01221f8a7714359b6db9baddee936a57af86dea0c27db5d107950dc2cbb852b85127b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed30276df3a84c79d6c856a1b40a6b2b519798f2e8232a8a648503a2a8e4bbe37500000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec014bed7647ed9d6920c754819ead8e23cc8e321c19ff2c9314058fd7e0304e4f0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010199ce8f5a9bc442f37ae170598a9bc90d17eadab6581779c9676a0e56010b200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000137a50b2142df7ae23ebdfc15bd940d38d013d3d46da25ee9d248442b150e1d51c955dbf68fd3e5e6fe974bbc136083ce8fbf744d72c1d3a957bf3b7908204cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000158fbbf4bb58fba04c0acb15f15347c48b3ea680f8d7dae2bb1e3b0c4be182ff000000039f55b7ce0d170ccac58c2f5c09bcfdcbdbb3f065dfee08bda6425eff163677ea1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003011be06754b8c232b8bad9dda35ea0bc820319091857b0d62e12e58618e8cdc8d0000018027e6d565e3b36446313ccd1c2cbfd4f5f4c66692ff2619bb8a2ae6ccfcb49f2100000200039266211c93fc4c8fc9bd6e8be0264f563b0c6f0ef927d2ac1d2e76adf1eed3000000061ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065c3664a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000000ec2b4787064785b51ae3daeb9ad6dc786c905f32635e2d4a70bf62b0ce6823b0f830d416d16949744f7f9395c3ed22ae5ee0b919e07ecf382b88e983e18f6e50ec968a693b4b39f1e2ad0c8c91bc0ea98d1b6504675b0383de879137a48aff5068c8b6b058f859d595bd79c3c5d9e0147d17c1e553890ae341eeefa20da686a0906bca10001001c955dbf68fd3e5e6fe974bbc136083ce8fbf744d72c1d3a957bf3b7908204cd068c8b6b058f859d595bd79c3c5d9e0147d17c1e553890ae341eeefa20da686a00000000000000000000000000000000000000000906bca100000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004158fbbf4bb58fba04c0acb15f15347c48b3ea680f8d7dae2bb1e3b0c4be182ff000000039f55b7ce0d170ccac58c2f5c09bcfdcbdbb3f065dfee08bda6425eff163677ea1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003011be06754b8c232b8bad9dda35ea0bc820319091857b0d62e12e58618e8cdc8d0000018027e6d565e3b36446313ccd1c2cbfd4f5f4c66692ff2619bb8a2ae6ccfcb49f2100000200039266211c93fc4c8fc9bd6e8be0264f563b0c6f0ef927d2ac1d2e76adf1eed3000000061ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000800000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065c3664a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f10bc53103bb3e974ee4441bbe849027229a23b7f3100bb2df269c258020a64020bb69a53e478ddca00f0db14f1a0e159db238ee78e48c5d9a74f8e3487ad84a027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed217b7dd03baa47011fce268533a0d5a875b7195d261d4b89b8f1096bce3177e400000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec014bed7647ed9d6920c754819ead8e23cc8e321c19ff2c9314058fd7e0304e4f0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex index c3d66a35818..9bd4da6a0eb 100644 --- a/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex +++ b/yarn-project/noir-protocol-circuits/src/fixtures/nested-call-private-kernel-ordering.hex @@ -1 +1 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000274dfff4000c36b779b454ae6dff6ecd8173983918199155d1029d53dca751200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d33d46c4746de18423e294230bb303736a3fffbde9f35dfd5b08bcd95137f23000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2cf249761616d0931073ab1ec446b59772ed60218564fa07628b885ed92017000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021d14d843a3659fd3c313445e1e3db070dde06e9041f5f65ec892ffe0189546e30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005560812314b847437db67eb287e4dc6100000000000000000000000000000000aeef84c34101583ef2400aaa128d73df000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000000f800000000000000000000000000000000000000000000000000000000000000041c1d34487db43700811410f1123e682c52e2c1567e0322647cfea3826e0d5ec200000000000000000000000000000000000000000000000000000000000000000000665a22f6bde0a5a80c7acb02d4acb772dbfe4e117eb142653d46b4b25b0500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e00000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011ade16c0a93966ebd5d022b084874443007fc6834d8db2094d974a604490ebe123ef56e8a650a17d8ba4b5f38562cebb89de0dee06800d29d4a37095b9f690de275269600f0f2ea6f3b92e16eed77f829447c3e26dedf0da785ada854cef7a2a0000665a22f6bde0a5a80c7acb02d4acb772dbfe4e117eb142653d46b4b25b05287545bf11d1995f3010eaeffd8c07a749e105ddf3081d73424a48b41f7a8d8a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000000c365d7da202db8b950995d635e5a847c352f888ef69628cf7f1aa78c027e08e229f4be84607d950582d9a975e96a1d5ed99837752dbf00745dbc627d2ffeaa425a05da014c399ae3c8bf6fc6cec27e7f142a3b58272b43723af9babf107ac9f0274dfff4000c36b779b454ae6dff6ecd8173983918199155d1029d53dca75120000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d33d46c4746de18423e294230bb303736a3fffbde9f35dfd5b08bcd95137f23000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d14d843a3659fd3c313445e1e3db070dde06e9041f5f65ec892ffe0189546e3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010a2cf249761616d0931073ab1ec446b59772ed60218564fa07628b885ed9201700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000001000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008af3070304ed3fe4a59f23b0d6a9ee0c3c9836cdfa3b594511399cae943acce000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023e6072dde738681665908c49d2a1e0d3688d2eb5c68a82dfc049e3e32bdd754000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c5bb9e6968823917533dd92b0d3066c475270844ab7843db4b684e36933d6bf000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000021ef53c68b70daa61fa4740c71d43836a8b7a51196a38f4a80f974144856459dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a37978f0dc81bf15851be2674da72461000000000000000000000000000000000d996a1d3cab7b7dc6f302245cbd3e1a000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000000f80000000000000000000000000000000000000000000000000000000000000004040cc2d6a57a9ed70de05ba838f36237b0fd89a4454bd5769cfcb70ab5ec0fb300000000000000000000000000000000000000002cec24fdcf1a1fd1e97fffe8c3327b22810b1aa820710e44ae757aa5561aea570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000001ed250ed73db6e70805c4efcf0056e8695b79cd3ba418e827c184dee6c6fb0e0000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012e6c276e1ef4755f6fda143424585d7ddb8018de978b1afc956ee1796ae53dca0dd6412b0443036d4c7c9a65dd938a1f2fb6a2fdda1b71629299a60054082cac0e97cbc43795084338d12e0a1897f712ee9ab5b6cc96387aaf1100daab06b3792cec24fdcf1a1fd1e97fffe8c3327b22810b1aa820710e44ae757aa5561aea5712e3d6beb3b820ec5fb1f101423c55c8f5567eb26a8cfc9e987dc6ab664307a600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001cb65dbae98f5e210e6590374976e670a34ab8701a89fdfca94c820d2b69462f1e6d17394272647745ee507f2d01b6e6d80fe2371fff952dd6e03d8874302758257ecd5435574bb3e5a795c1d6561c78545fc0abc3f183fff7bdc75974ba19af08af3070304ed3fe4a59f23b0d6a9ee0c3c9836cdfa3b594511399cae943acce0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000023e6072dde738681665908c49d2a1e0d3688d2eb5c68a82dfc049e3e32bdd754000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ef53c68b70daa61fa4740c71d43836a8b7a51196a38f4a80f974144856459dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c5bb9e6968823917533dd92b0d3066c475270844ab7843db4b684e36933d6bf00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000001000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits/src/index.test.ts b/yarn-project/noir-protocol-circuits/src/index.test.ts index 2afc9ce12c4..d8d854f4df9 100644 --- a/yarn-project/noir-protocol-circuits/src/index.test.ts +++ b/yarn-project/noir-protocol-circuits/src/index.test.ts @@ -17,7 +17,8 @@ import { computeContractAddressFromPartial, computePublicKeysHash, } from '@aztec/circuits.js'; -import { computeTxHash } from '@aztec/circuits.js/abis'; +import { computeTxHash, computeVarArgsHash } from '@aztec/circuits.js/abis'; +import { times } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; @@ -130,7 +131,7 @@ describe('Noir compatibility tests (interop_testing.nr)', () => { new Fr(1), new Fr(2), new Fr(3), - new EthAddress(numberToBuffer(1)), + EthAddress.fromField(new Fr(1)), ); const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), @@ -149,7 +150,7 @@ describe('Noir compatibility tests (interop_testing.nr)', () => { new Fr(1), new Fr(2), new Fr(3), - new EthAddress(numberToBuffer(1)), + EthAddress.fromField(new Fr(1)), ); const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), @@ -181,13 +182,10 @@ describe('Noir compatibility tests (interop_testing.nr)', () => { const publicCallStackItem = new PublicCallStackItem(contractAddress, functionData, appPublicInputs, true); expect(publicCallStackItem.hash().toString()).toMatchSnapshot(); }); -}); -function numberToBuffer(value: number) { - // This can be used to convert a number to a buffer - // and used as an EthAddress or AztecAddress. - // - // I think the EthAddress taking in 32 bytes is - // not great, but I'll take advantage of it here. - return new Fr(value).toBuffer(); -} + it('Var args hash matches noir', () => { + const args = times(800, i => new Fr(i)); + const res = computeVarArgsHash(args); + expect(res).toMatchSnapshot(); + }); +}); diff --git a/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts b/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts index 7c61e33590c..2f8bad46b4e 100644 --- a/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts +++ b/yarn-project/noir-protocol-circuits/src/noir_test_gen.test.ts @@ -12,7 +12,7 @@ import { computeSaltedInitializationHash, } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { Pedersen, StandardTree } from '@aztec/merkle-tree'; import { ContractClass, ContractInstance } from '@aztec/types/contracts'; @@ -94,7 +94,7 @@ describe('Data generation for noir tests', () => { const indexes = new Array(128).fill(null).map((_, i) => BigInt(i)); const leaves = indexes.map(i => new Fr(i + 1n).toBuffer()); - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const noteHashTree = new StandardTree( db, diff --git a/yarn-project/noir-protocol-circuits/src/type_conversion.ts b/yarn-project/noir-protocol-circuits/src/type_conversion.ts index 2e25b5256e0..f7a2b1a845a 100644 --- a/yarn-project/noir-protocol-circuits/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits/src/type_conversion.ts @@ -1,5 +1,6 @@ import { ARCHIVE_HEIGHT, + AccumulatedMetaData, AggregationObject, AppendOnlyTreeSnapshot, AztecAddress, @@ -27,13 +28,15 @@ import { KernelCircuitPublicInputs, KernelCircuitPublicInputsFinal, MAX_NEW_COMMITMENTS_PER_TX, + MAX_NEW_COMMITMENTS_PER_TX_META, MAX_NEW_CONTRACTS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX_META, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_READ_REQUESTS_PER_TX, @@ -45,7 +48,6 @@ import { NullifierKeyValidationRequest, NullifierKeyValidationRequestContext, NullifierLeafPreimage, - OptionallyRevealedData, PUBLIC_DATA_TREE_HEIGHT, PartialStateReference, Point, @@ -97,7 +99,6 @@ import { GrumpkinPoint as NoirPoint, NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, - OptionallyRevealedData as OptionallyRevealedDataNoir, PrivateCallData as PrivateCallDataNoir, PrivateCallStackItem as PrivateCallStackItemNoir, PrivateCircuitPublicInputs as PrivateCircuitPublicInputsNoir, @@ -115,6 +116,7 @@ import { PrivateKernelInputsInner as PrivateKernelInputsInnerNoir, } from './types/private_kernel_inner_types.js'; import { + AccumulatedMetaData as AccumulatedMetaDataNoir, FinalAccumulatedData as FinalAccumulatedDataNoir, KernelCircuitPublicInputsFinal as KernelCircuitPublicInputsFinalNoir, PrivateKernelInputsOrdering as PrivateKernelInputsOrderingNoir, @@ -642,6 +644,7 @@ export function mapPrivateCircuitPublicInputsToNoir( contract_deployment_data: mapContractDeploymentDataToNoir(privateCircuitPublicInputs.contractDeploymentData), chain_id: mapFieldToNoir(privateCircuitPublicInputs.chainId), version: mapFieldToNoir(privateCircuitPublicInputs.version), + meta_hwm: mapFieldToNoir(Fr.ZERO), }; } @@ -653,9 +656,8 @@ export function mapPrivateCircuitPublicInputsToNoir( export function mapPrivateCallStackItemToNoir(privateCallStackItem: PrivateCallStackItem): PrivateCallStackItemNoir { return { contract_address: mapAztecAddressToNoir(privateCallStackItem.contractAddress), - public_inputs: mapPrivateCircuitPublicInputsToNoir(privateCallStackItem.publicInputs), - is_execution_request: privateCallStackItem.isExecutionRequest, function_data: mapFunctionDataToNoir(privateCallStackItem.functionData), + public_inputs: mapPrivateCircuitPublicInputsToNoir(privateCallStackItem.publicInputs), }; } @@ -754,46 +756,6 @@ export function mapSha256HashToNoir(hash: Buffer): FixedLengthArray { return to2Fields(hash).map(mapFieldToNoir) as FixedLengthArray; } -/** - * Maps optionally revealed data from noir to the parsed type. - * @param optionallyRevealedData - The noir optionally revealed data. - * @returns The parsed optionally revealed data. - */ -export function mapOptionallyRevealedDataFromNoir( - optionallyRevealedData: OptionallyRevealedDataNoir, -): OptionallyRevealedData { - return new OptionallyRevealedData( - mapFieldFromNoir(optionallyRevealedData.call_stack_item_hash), - mapFunctionDataFromNoir(optionallyRevealedData.function_data), - mapFieldFromNoir(optionallyRevealedData.vk_hash), - mapEthAddressFromNoir(optionallyRevealedData.portal_contract_address), - optionallyRevealedData.pay_fee_from_l1, - optionallyRevealedData.pay_fee_from_public_l2, - optionallyRevealedData.called_from_l1, - optionallyRevealedData.called_from_public_l2, - ); -} - -/** - * Maps optionally revealed data to noir optionally revealed data. - * @param optionallyRevealedData - The optionally revealed data. - * @returns The noir optionally revealed data. - */ -export function mapOptionallyRevealedDataToNoir( - optionallyRevealedData: OptionallyRevealedData, -): OptionallyRevealedDataNoir { - return { - call_stack_item_hash: mapFieldToNoir(optionallyRevealedData.callStackItemHash), - function_data: mapFunctionDataToNoir(optionallyRevealedData.functionData), - vk_hash: mapFieldToNoir(optionallyRevealedData.vkHash), - portal_contract_address: mapEthAddressToNoir(optionallyRevealedData.portalContractAddress), - pay_fee_from_l1: optionallyRevealedData.payFeeFromL1, - pay_fee_from_public_l2: optionallyRevealedData.payFeeFromPublicL2, - called_from_l1: optionallyRevealedData.calledFromL1, - called_from_public_l2: optionallyRevealedData.calledFromPublicL2, - }; -} - /** * Maps new contract data from noir to the parsed type. * @param newContractData - The noir new contract data. @@ -880,8 +842,6 @@ export function mapCombinedAccumulatedDataFromNoir( combinedAccumulatedData: CombinedAccumulatedDataNoir, ): CombinedAccumulatedData { return new CombinedAccumulatedData( - // TODO aggregation object - AggregationObject.makeFake(), mapTupleFromNoir(combinedAccumulatedData.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( combinedAccumulatedData.nullifier_key_validation_requests, @@ -906,11 +866,6 @@ export function mapCombinedAccumulatedDataFromNoir( mapFieldFromNoir(combinedAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(combinedAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir(combinedAccumulatedData.new_contracts, MAX_NEW_CONTRACTS_PER_TX, mapNewContractDataFromNoir), - mapTupleFromNoir( - combinedAccumulatedData.optionally_revealed_data, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, - mapOptionallyRevealedDataFromNoir, - ), mapTupleFromNoir( combinedAccumulatedData.public_data_update_requests, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -931,8 +886,6 @@ export function mapCombinedAccumulatedDataFromNoir( */ export function mapFinalAccumulatedDataFromNoir(finalAccumulatedData: FinalAccumulatedDataNoir): FinalAccumulatedData { return new FinalAccumulatedData( - // TODO aggregation object - AggregationObject.makeFake(), mapTupleFromNoir(finalAccumulatedData.new_commitments, MAX_NEW_COMMITMENTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(finalAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -951,10 +904,22 @@ export function mapFinalAccumulatedDataFromNoir(finalAccumulatedData: FinalAccum mapFieldFromNoir(finalAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(finalAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir(finalAccumulatedData.new_contracts, MAX_NEW_CONTRACTS_PER_TX, mapNewContractDataFromNoir), + ); +} + +/** + * Maps accumulated data in the Tx's meta phase to the parsed type. + * @param accumulatedMetaData - The noir accumulated meta data. + * @returns The parsed accumulated meta data. + */ +export function mapAccumulatedMetaDataFromNoir(accumulatedMetaData: AccumulatedMetaDataNoir): AccumulatedMetaData { + return new AccumulatedMetaData( + mapTupleFromNoir(accumulatedMetaData.new_commitments, MAX_NEW_COMMITMENTS_PER_TX_META, mapSideEffectFromNoir), + mapTupleFromNoir(accumulatedMetaData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX_META, mapSideEffectLinkedFromNoir), mapTupleFromNoir( - finalAccumulatedData.optionally_revealed_data, - MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX, - mapOptionallyRevealedDataFromNoir, + accumulatedMetaData.public_call_stack, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX_META, + mapCallRequestFromNoir, ), ); } @@ -968,7 +933,6 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData: CombinedAccumulatedData, ): CombinedAccumulatedDataNoir { return { - aggregation_object: {}, read_requests: mapTuple(combinedAccumulatedData.readRequests, mapSideEffectToNoir), nullifier_key_validation_requests: mapTuple( combinedAccumulatedData.nullifierKeyValidationRequests, @@ -984,7 +948,6 @@ export function mapCombinedAccumulatedDataToNoir( encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.unencryptedLogPreimagesLength), new_contracts: mapTuple(combinedAccumulatedData.newContracts, mapNewContractDataToNoir), - optionally_revealed_data: mapTuple(combinedAccumulatedData.optionallyRevealedData, mapOptionallyRevealedDataToNoir), public_data_update_requests: mapTuple( combinedAccumulatedData.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir, @@ -1069,6 +1032,9 @@ export function mapKernelCircuitPublicInputsFromNoir( kernelCircuitPublicInputs: KernelCircuitPublicInputsNoir, ): KernelCircuitPublicInputs { return new KernelCircuitPublicInputs( + // TODO aggregation object + AggregationObject.makeFake(), + mapFieldFromNoir(kernelCircuitPublicInputs.meta_hwm), mapCombinedAccumulatedDataFromNoir(kernelCircuitPublicInputs.end), mapCombinedConstantDataFromNoir(kernelCircuitPublicInputs.constants), kernelCircuitPublicInputs.is_private, @@ -1084,6 +1050,8 @@ export function mapKernelCircuitPublicInputsToNoir( publicInputs: KernelCircuitPublicInputs, ): KernelCircuitPublicInputsNoir { return { + aggregation_object: {}, + meta_hwm: mapFieldToNoir(publicInputs.metaHwm), end: mapCombinedAccumulatedDataToNoir(publicInputs.end), constants: mapCombinedConstantDataToNoir(publicInputs.constants), is_private: publicInputs.isPrivate, @@ -1099,6 +1067,9 @@ export function mapKernelCircuitPublicInputsFinalFromNoir( publicInputs: KernelCircuitPublicInputsFinalNoir, ): KernelCircuitPublicInputsFinal { return new KernelCircuitPublicInputsFinal( + AggregationObject.makeFake(), + mapFieldFromNoir(publicInputs.meta_hwm), + mapAccumulatedMetaDataFromNoir(publicInputs.end_meta), mapFinalAccumulatedDataFromNoir(publicInputs.end), mapCombinedConstantDataFromNoir(publicInputs.constants), publicInputs.is_private, @@ -1150,6 +1121,8 @@ export function mapGlobalVariablesToNoir(globalVariables: GlobalVariables): Glob version: mapFieldToNoir(globalVariables.version), block_number: mapFieldToNoir(globalVariables.blockNumber), timestamp: mapFieldToNoir(globalVariables.timestamp), + coinbase: mapEthAddressToNoir(globalVariables.coinbase), + fee_recipient: mapAztecAddressToNoir(globalVariables.feeRecipient), }; } @@ -1175,6 +1148,8 @@ export function mapGlobalVariablesFromNoir(globalVariables: GlobalVariablesNoir) mapFieldFromNoir(globalVariables.version), mapFieldFromNoir(globalVariables.block_number), mapFieldFromNoir(globalVariables.timestamp), + mapEthAddressFromNoir(globalVariables.coinbase), + mapAztecAddressFromNoir(globalVariables.fee_recipient), ); } diff --git a/yarn-project/p2p/src/client/p2p_client.test.ts b/yarn-project/p2p/src/client/p2p_client.test.ts index 0ca27e09752..d0c9ba8da8a 100644 --- a/yarn-project/p2p/src/client/p2p_client.test.ts +++ b/yarn-project/p2p/src/client/p2p_client.test.ts @@ -1,5 +1,6 @@ import { L2BlockSource, mockTx } from '@aztec/circuit-types'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { expect, jest } from '@jest/globals'; @@ -22,7 +23,7 @@ describe('In-Memory P2P Client', () => { let kvStore: AztecKVStore; let client: P2PClient; - beforeEach(async () => { + beforeEach(() => { txPool = { addTxs: jest.fn(), getTxByHash: jest.fn().mockReturnValue(undefined), @@ -41,7 +42,7 @@ describe('In-Memory P2P Client', () => { blockSource = new MockBlockSource(); - kvStore = await AztecLmdbStore.openTmp(); + kvStore = openTmpStore(); client = new P2PClient(kvStore, blockSource, txPool, p2pService); }); diff --git a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts index fe030abe6d7..9dc6e8ddc11 100644 --- a/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts +++ b/yarn-project/p2p/src/tx_pool/aztec_kv_tx_pool.test.ts @@ -1,12 +1,12 @@ -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { AztecKVTxPool } from './aztec_kv_tx_pool.js'; import { describeTxPool } from './tx_pool_test_suite.js'; describe('In-Memory TX pool', () => { let txPool: AztecKVTxPool; - beforeEach(async () => { - txPool = new AztecKVTxPool(await AztecLmdbStore.openTmp()); + beforeEach(() => { + txPool = new AztecKVTxPool(openTmpStore()); }); describeTxPool(() => txPool); diff --git a/yarn-project/package.json b/yarn-project/package.json index 489e0f42ecc..4d68e44fc0b 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -17,7 +17,7 @@ }, "workspaces": [ "accounts", - "acir-simulator", + "simulator", "archiver", "aztec-faucet", "aztec-node", @@ -40,6 +40,7 @@ "noir-protocol-circuits", "p2p", "p2p-bootstrap", + "protocol-contracts", "prover-client", "rollup-provider", "sequencer-client", diff --git a/yarn-project/acir-simulator/.eslintrc.cjs b/yarn-project/protocol-contracts/.eslintrc.cjs similarity index 100% rename from yarn-project/acir-simulator/.eslintrc.cjs rename to yarn-project/protocol-contracts/.eslintrc.cjs diff --git a/yarn-project/protocol-contracts/.gitignore b/yarn-project/protocol-contracts/.gitignore new file mode 100644 index 00000000000..7912fc48c7d --- /dev/null +++ b/yarn-project/protocol-contracts/.gitignore @@ -0,0 +1 @@ +/src/artifacts diff --git a/yarn-project/protocol-contracts/README.md b/yarn-project/protocol-contracts/README.md new file mode 100644 index 00000000000..a8d9392ed5d --- /dev/null +++ b/yarn-project/protocol-contracts/README.md @@ -0,0 +1,7 @@ +# Protocol Contracts + +Noir contract artifacts used to power the Aztec Network protocol, along with their canonical deployment information. + +Includes: +- Contract class registerer +- Contract instance deployer \ No newline at end of file diff --git a/yarn-project/protocol-contracts/package.json b/yarn-project/protocol-contracts/package.json new file mode 100644 index 00000000000..74f2eb153ea --- /dev/null +++ b/yarn-project/protocol-contracts/package.json @@ -0,0 +1,69 @@ +{ + "name": "@aztec/protocol-contracts", + "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/yarn-project/protocol-contracts", + "description": "Canonical Noir contracts for the Aztec Network", + "version": "0.1.0", + "type": "module", + "exports": { + ".": "./dest/index.js", + "./*": "./dest/*/index.js" + }, + "typedocOptions": { + "entryPoints": [ + "./src/index.ts", + "./src/class-registerer/index.ts", + "./src/instance-deployer/index.ts" + ], + "name": "Protocol Contracts", + "tsconfig": "./tsconfig.json" + }, + "scripts": { + "build": "yarn clean && yarn build:copy-contracts && tsc -b", + "build:copy-contracts": "./scripts/copy-contracts.sh", + "build:dev": "tsc -b --watch", + "build:ts": "tsc -b", + "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", + "formatting": "run -T prettier --check ./src && run -T eslint ./src", + "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" + }, + "inherits": [ + "../package.common.json", + "./package.local.json" + ], + "jest": { + "preset": "ts-jest/presets/default-esm", + "moduleNameMapper": { + "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" + }, + "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", + "rootDir": "./src" + }, + "dependencies": { + "@aztec/circuits.js": "workspace:^", + "@aztec/foundation": "workspace:^", + "@aztec/types": "workspace:^", + "lodash.omit": "^4.5.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@jest/globals": "^29.5.0", + "@types/jest": "^29.5.0", + "@types/lodash.omit": "^4.5.9", + "@types/node": "^18.7.23", + "jest": "^29.5.0", + "jest-mock-extended": "^3.0.3", + "ts-jest": "^29.1.0", + "ts-loader": "^9.4.4", + "ts-node": "^10.9.1", + "typescript": "^5.0.4" + }, + "files": [ + "dest", + "src", + "!*.test.*" + ], + "engines": { + "node": ">=18" + } +} diff --git a/yarn-project/protocol-contracts/package.local.json b/yarn-project/protocol-contracts/package.local.json new file mode 100644 index 00000000000..def45a001a2 --- /dev/null +++ b/yarn-project/protocol-contracts/package.local.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "build": "yarn clean && yarn build:copy-contracts && tsc -b", + "build:copy-contracts": "./scripts/copy-contracts.sh", + "build:dev": "tsc -b --watch", + "build:ts": "tsc -b", + "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" + } +} diff --git a/yarn-project/protocol-contracts/scripts/copy-contracts.sh b/yarn-project/protocol-contracts/scripts/copy-contracts.sh new file mode 100755 index 00000000000..51e4f4a5e5b --- /dev/null +++ b/yarn-project/protocol-contracts/scripts/copy-contracts.sh @@ -0,0 +1,11 @@ +#! /bin/bash +set -euo pipefail +mkdir -p ./src/artifacts + +contracts=(contract_class_registerer_contract-ContractClassRegisterer contract_instance_deployer_contract-ContractInstanceDeployer) + +for contract in "${contracts[@]}"; do + cp "../noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json +done + +yarn run -T prettier -w ./src/artifacts \ No newline at end of file diff --git a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap new file mode 100644 index 00000000000..1e0c5fe95d3 --- /dev/null +++ b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap @@ -0,0 +1,635 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ClassRegisterer returns canonical protocol contract 1`] = ` +{ + "address": AztecAddress { + "asBigInt": 18885476286413803383198269230770707720385495724494788057562984154330701020921n, + "asBuffer": { + "data": [ + 41, + 192, + 205, + 0, + 0, + 149, + 27, + 186, + 138, + 245, + 32, + 173, + 85, + 19, + 204, + 83, + 217, + 240, + 65, + 60, + 90, + 36, + 167, + 42, + 75, + 168, + 193, + 120, + 148, + 192, + 190, + 249, + ], + "type": "Buffer", + }, + }, + "contractClass": { + "artifactHash": Fr { + "asBigInt": 12987763002449886210249343009930617501836480764589027470816200726753333386077n, + "asBuffer": { + "data": [ + 28, + 182, + 208, + 56, + 31, + 162, + 181, + 120, + 194, + 173, + 145, + 119, + 205, + 23, + 92, + 17, + 148, + 169, + 179, + 132, + 128, + 198, + 168, + 109, + 135, + 242, + 101, + 160, + 56, + 218, + 155, + 93, + ], + "type": "Buffer", + }, + }, + "id": Fr { + "asBigInt": 15610368298223903406763887747663253144646438360806401290390854210044956890867n, + "asBuffer": { + "data": [ + 34, + 131, + 39, + 197, + 16, + 11, + 210, + 53, + 13, + 80, + 129, + 233, + 196, + 47, + 124, + 112, + 85, + 229, + 146, + 176, + 58, + 247, + 80, + 38, + 80, + 100, + 198, + 59, + 105, + 209, + 214, + 243, + ], + "type": "Buffer", + }, + }, + "packedBytecode": { + "data": [ + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + "privateFunctions": [ + { + "isInternal": false, + "selector": FunctionSelector { + "value": 588837637, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + { + "isInternal": false, + "selector": FunctionSelector { + "value": 595568763, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + { + "isInternal": false, + "selector": FunctionSelector { + "value": 1669488881, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + { + "isInternal": false, + "selector": FunctionSelector { + "value": 2432309179, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "privateFunctionsRoot": Fr { + "asBigInt": 14149643440615160691253002398502794418486578915412752764304101313202744681431n, + "asBuffer": { + "data": [ + 31, + 72, + 106, + 20, + 204, + 180, + 255, + 137, + 103, + 217, + 28, + 197, + 42, + 211, + 3, + 8, + 107, + 19, + 4, + 29, + 137, + 6, + 131, + 49, + 212, + 129, + 225, + 242, + 112, + 231, + 99, + 215, + ], + "type": "Buffer", + }, + }, + "publicBytecodeCommitment": Fr { + "asBigInt": 13424778679590722659186070167781649503057405647123863047387123265455936508181n, + "asBuffer": { + "data": [ + 29, + 174, + 39, + 204, + 127, + 226, + 175, + 52, + 95, + 22, + 2, + 83, + 190, + 56, + 117, + 212, + 73, + 167, + 233, + 186, + 107, + 214, + 135, + 71, + 216, + 125, + 78, + 112, + 84, + 184, + 17, + 21, + ], + "type": "Buffer", + }, + }, + "publicFunctions": [], + "version": 1, + }, + "instance": { + "address": AztecAddress { + "asBigInt": 18885476286413803383198269230770707720385495724494788057562984154330701020921n, + "asBuffer": { + "data": [ + 41, + 192, + 205, + 0, + 0, + 149, + 27, + 186, + 138, + 245, + 32, + 173, + 85, + 19, + 204, + 83, + 217, + 240, + 65, + 60, + 90, + 36, + 167, + 42, + 75, + 168, + 193, + 120, + 148, + 192, + 190, + 249, + ], + "type": "Buffer", + }, + }, + "contractClassId": Fr { + "asBigInt": 15610368298223903406763887747663253144646438360806401290390854210044956890867n, + "asBuffer": { + "data": [ + 34, + 131, + 39, + 197, + 16, + 11, + 210, + 53, + 13, + 80, + 129, + 233, + 196, + 47, + 124, + 112, + 85, + 229, + 146, + 176, + 58, + 247, + 80, + 38, + 80, + 100, + 198, + 59, + 105, + 209, + 214, + 243, + ], + "type": "Buffer", + }, + }, + "initializationHash": Fr { + "asBigInt": 5411687428194306823799197943510367074755080310726877398642044502900791103391n, + "asBuffer": { + "data": [ + 11, + 246, + 232, + 18, + 241, + 75, + 176, + 41, + 247, + 203, + 156, + 141, + 168, + 54, + 125, + 217, + 124, + 6, + 142, + 120, + 141, + 79, + 33, + 0, + 127, + 217, + 112, + 20, + 235, + 168, + 207, + 159, + ], + "type": "Buffer", + }, + }, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "publicKeysHash": Fr { + "asBigInt": 17954372136461894568820199868962143715279932924957662285438325406238856880109n, + "asBuffer": { + "data": [ + 39, + 177, + 208, + 131, + 154, + 91, + 35, + 186, + 241, + 42, + 141, + 25, + 91, + 24, + 172, + 40, + 143, + 207, + 64, + 26, + 251, + 47, + 112, + 184, + 164, + 181, + 41, + 237, + 229, + 250, + 159, + 237, + ], + "type": "Buffer", + }, + }, + "salt": Fr { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "version": 1, + }, +} +`; diff --git a/yarn-project/protocol-contracts/src/class-registerer/artifact.ts b/yarn-project/protocol-contracts/src/class-registerer/artifact.ts new file mode 100644 index 00000000000..2a3ca423ce6 --- /dev/null +++ b/yarn-project/protocol-contracts/src/class-registerer/artifact.ts @@ -0,0 +1,8 @@ +import { loadContractArtifact } from '@aztec/types/abi'; +import { NoirCompiledContract } from '@aztec/types/noir'; + +import ContractClassRegistererJson from '../artifacts/ContractClassRegisterer.json' assert { type: 'json' }; + +export const ContractClassRegistererArtifact = loadContractArtifact( + ContractClassRegistererJson as NoirCompiledContract, +); diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.test.ts b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts new file mode 100644 index 00000000000..bfe56c7340c --- /dev/null +++ b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts @@ -0,0 +1,13 @@ +import omit from 'lodash.omit'; + +import { ClassRegistererAddress, getCanonicalClassRegisterer } from './index.js'; + +describe('ClassRegisterer', () => { + it('returns canonical protocol contract', () => { + const contract = getCanonicalClassRegisterer(); + contract.contractClass.privateFunctions.sort((a, b) => a.selector.value - b.selector.value); + contract.contractClass.publicFunctions.sort((a, b) => a.selector.value - b.selector.value); + expect(omit(contract, 'artifact')).toMatchSnapshot(); + expect(contract.address.toString()).toEqual(ClassRegistererAddress.toString()); + }); +}); diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.ts b/yarn-project/protocol-contracts/src/class-registerer/index.ts new file mode 100644 index 00000000000..a4885c7d975 --- /dev/null +++ b/yarn-project/protocol-contracts/src/class-registerer/index.ts @@ -0,0 +1,17 @@ +import { AztecAddress } from '@aztec/circuits.js'; + +import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; +import { ContractClassRegistererArtifact } from './artifact.js'; + +/** Returns the canonical deployment of the class registerer contract. */ +export function getCanonicalClassRegisterer(): ProtocolContract { + return getCanonicalProtocolContract(ContractClassRegistererArtifact, 1); +} + +/** + * Address of the canonical class registerer. + * @remarks This should not change often, hence we hardcode it to save from having to recompute it every time. + */ +export const ClassRegistererAddress = AztecAddress.fromString( + '0x29c0cd0000951bba8af520ad5513cc53d9f0413c5a24a72a4ba8c17894c0bef9', +); diff --git a/yarn-project/protocol-contracts/src/index.ts b/yarn-project/protocol-contracts/src/index.ts new file mode 100644 index 00000000000..f8cc9c7109a --- /dev/null +++ b/yarn-project/protocol-contracts/src/index.ts @@ -0,0 +1 @@ +export { ProtocolContract } from './protocol_contract.js'; diff --git a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap new file mode 100644 index 00000000000..3ca5288c62a --- /dev/null +++ b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap @@ -0,0 +1,543 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`InstanceDeployer returns canonical protocol contract 1`] = ` +{ + "address": AztecAddress { + "asBigInt": 10674890382018500410451173831129216683967953609468942304388116555335197334423n, + "asBuffer": { + "data": [ + 23, + 153, + 198, + 26, + 161, + 4, + 48, + 191, + 111, + 236, + 70, + 103, + 156, + 76, + 183, + 108, + 62, + 209, + 44, + 216, + 182, + 231, + 62, + 215, + 56, + 157, + 90, + 226, + 150, + 173, + 27, + 151, + ], + "type": "Buffer", + }, + }, + "contractClass": { + "artifactHash": Fr { + "asBigInt": 1546915255081493429210407932347415325264105027406908683791229627179136590869n, + "asBuffer": { + "data": [ + 3, + 107, + 133, + 227, + 201, + 147, + 91, + 223, + 147, + 254, + 104, + 143, + 129, + 46, + 252, + 227, + 185, + 74, + 0, + 254, + 227, + 11, + 162, + 57, + 80, + 42, + 239, + 244, + 210, + 18, + 36, + 21, + ], + "type": "Buffer", + }, + }, + "id": Fr { + "asBigInt": 9040462806880011027940587321357143576447825874691049241890511565119666681463n, + "asBuffer": { + "data": [ + 19, + 252, + 184, + 122, + 123, + 192, + 60, + 228, + 9, + 114, + 248, + 85, + 174, + 199, + 235, + 168, + 55, + 50, + 74, + 245, + 238, + 197, + 231, + 41, + 29, + 105, + 17, + 105, + 36, + 126, + 118, + 119, + ], + "type": "Buffer", + }, + }, + "packedBytecode": { + "data": [ + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + "privateFunctions": [ + { + "isInternal": false, + "selector": FunctionSelector { + "value": 2285065643, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + { + "isInternal": false, + "selector": FunctionSelector { + "value": 2432309179, + }, + "vkHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "privateFunctionsRoot": Fr { + "asBigInt": 10175937322611504760053163396285173722489074882473725995897130952520062304283n, + "asBuffer": { + "data": [ + 22, + 127, + 96, + 93, + 15, + 118, + 143, + 145, + 206, + 97, + 129, + 56, + 23, + 230, + 12, + 1, + 170, + 115, + 219, + 197, + 231, + 133, + 116, + 128, + 74, + 71, + 30, + 51, + 115, + 5, + 128, + 27, + ], + "type": "Buffer", + }, + }, + "publicBytecodeCommitment": Fr { + "asBigInt": 13424778679590722659186070167781649503057405647123863047387123265455936508181n, + "asBuffer": { + "data": [ + 29, + 174, + 39, + 204, + 127, + 226, + 175, + 52, + 95, + 22, + 2, + 83, + 190, + 56, + 117, + 212, + 73, + 167, + 233, + 186, + 107, + 214, + 135, + 71, + 216, + 125, + 78, + 112, + 84, + 184, + 17, + 21, + ], + "type": "Buffer", + }, + }, + "publicFunctions": [], + "version": 1, + }, + "instance": { + "address": AztecAddress { + "asBigInt": 10674890382018500410451173831129216683967953609468942304388116555335197334423n, + "asBuffer": { + "data": [ + 23, + 153, + 198, + 26, + 161, + 4, + 48, + 191, + 111, + 236, + 70, + 103, + 156, + 76, + 183, + 108, + 62, + 209, + 44, + 216, + 182, + 231, + 62, + 215, + 56, + 157, + 90, + 226, + 150, + 173, + 27, + 151, + ], + "type": "Buffer", + }, + }, + "contractClassId": Fr { + "asBigInt": 9040462806880011027940587321357143576447825874691049241890511565119666681463n, + "asBuffer": { + "data": [ + 19, + 252, + 184, + 122, + 123, + 192, + 60, + 228, + 9, + 114, + 248, + 85, + 174, + 199, + 235, + 168, + 55, + 50, + 74, + 245, + 238, + 197, + 231, + 41, + 29, + 105, + 17, + 105, + 36, + 126, + 118, + 119, + ], + "type": "Buffer", + }, + }, + "initializationHash": Fr { + "asBigInt": 5411687428194306823799197943510367074755080310726877398642044502900791103391n, + "asBuffer": { + "data": [ + 11, + 246, + 232, + 18, + 241, + 75, + 176, + 41, + 247, + 203, + 156, + 141, + 168, + 54, + 125, + 217, + 124, + 6, + 142, + 120, + 141, + 79, + 33, + 0, + 127, + 217, + 112, + 20, + 235, + 168, + 207, + 159, + ], + "type": "Buffer", + }, + }, + "portalContractAddress": EthAddress { + "buffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "publicKeysHash": Fr { + "asBigInt": 17954372136461894568820199868962143715279932924957662285438325406238856880109n, + "asBuffer": { + "data": [ + 39, + 177, + 208, + 131, + 154, + 91, + 35, + 186, + 241, + 42, + 141, + 25, + 91, + 24, + 172, + 40, + 143, + 207, + 64, + 26, + 251, + 47, + 112, + 184, + 164, + 181, + 41, + 237, + 229, + 250, + 159, + 237, + ], + "type": "Buffer", + }, + }, + "salt": Fr { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 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, + ], + "type": "Buffer", + }, + }, + "version": 1, + }, +} +`; diff --git a/yarn-project/protocol-contracts/src/instance-deployer/artifact.ts b/yarn-project/protocol-contracts/src/instance-deployer/artifact.ts new file mode 100644 index 00000000000..3ae928ab045 --- /dev/null +++ b/yarn-project/protocol-contracts/src/instance-deployer/artifact.ts @@ -0,0 +1,8 @@ +import { loadContractArtifact } from '@aztec/types/abi'; +import { NoirCompiledContract } from '@aztec/types/noir'; + +import ContractInstanceDeployerJson from '../artifacts/ContractInstanceDeployer.json' assert { type: 'json' }; + +export const ContractInstanceDeployerArtifact = loadContractArtifact( + ContractInstanceDeployerJson as NoirCompiledContract, +); diff --git a/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts b/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts new file mode 100644 index 00000000000..463d2b42e2a --- /dev/null +++ b/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts @@ -0,0 +1,15 @@ +import omit from 'lodash.omit'; + +import { InstanceDeployerAddress, getCanonicalInstanceDeployer } from './index.js'; + +describe('InstanceDeployer', () => { + it('returns canonical protocol contract', () => { + // TODO(@spalladino): Consider sorting functions by selector when constructing the contract + // class, or even better, when calling loadContractArtifact from the Noir output. + const contract = getCanonicalInstanceDeployer(); + contract.contractClass.privateFunctions.sort((a, b) => a.selector.value - b.selector.value); + contract.contractClass.publicFunctions.sort((a, b) => a.selector.value - b.selector.value); + expect(omit(contract, 'artifact')).toMatchSnapshot(); + expect(contract.address.toString()).toEqual(InstanceDeployerAddress.toString()); + }); +}); diff --git a/yarn-project/protocol-contracts/src/instance-deployer/index.ts b/yarn-project/protocol-contracts/src/instance-deployer/index.ts new file mode 100644 index 00000000000..9605acf2def --- /dev/null +++ b/yarn-project/protocol-contracts/src/instance-deployer/index.ts @@ -0,0 +1,13 @@ +import { AztecAddress } from '@aztec/circuits.js'; + +import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; +import { ContractInstanceDeployerArtifact } from './artifact.js'; + +/** Returns the canonical deployment of the instance deployer contract. */ +export function getCanonicalInstanceDeployer(): ProtocolContract { + return getCanonicalProtocolContract(ContractInstanceDeployerArtifact, 1); +} + +export const InstanceDeployerAddress = AztecAddress.fromString( + '0x1799c61aa10430bf6fec46679c4cb76c3ed12cd8b6e73ed7389d5ae296ad1b97', +); diff --git a/yarn-project/protocol-contracts/src/protocol_contract.ts b/yarn-project/protocol-contracts/src/protocol_contract.ts new file mode 100644 index 00000000000..4f798ed4f48 --- /dev/null +++ b/yarn-project/protocol-contracts/src/protocol_contract.ts @@ -0,0 +1,33 @@ +import { AztecAddress, getContractClassFromArtifact, getContractInstanceFromDeployParams } from '@aztec/circuits.js'; +import { ContractArtifact } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; + +/** Represents a canonical contract in the protocol. */ +export interface ProtocolContract { + /** Canonical deployed instance. */ + instance: ContractInstanceWithAddress; + /** Contract class of this contract. */ + contractClass: ContractClassWithId; + /** Complete contract artifact. */ + artifact: ContractArtifact; + /** Deployment address for the canonical instance. */ + address: AztecAddress; +} + +/** Returns the canonical deployment a given artifact. */ +export function getCanonicalProtocolContract( + artifact: ContractArtifact, + salt: Fr | number | bigint, + initArgs: any[] = [], +): ProtocolContract { + // TODO(@spalladino): This computes the contract class from the artifact twice. + const contractClass = getContractClassFromArtifact(artifact); + const instance = getContractInstanceFromDeployParams(artifact, initArgs, new Fr(salt)); + return { + instance, + contractClass, + artifact, + address: instance.address, + }; +} diff --git a/yarn-project/protocol-contracts/tsconfig.json b/yarn-project/protocol-contracts/tsconfig.json new file mode 100644 index 00000000000..01c876235ce --- /dev/null +++ b/yarn-project/protocol-contracts/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "..", + "compilerOptions": { + "outDir": "dest", + "rootDir": "src", + "tsBuildInfoFile": ".tsbuildinfo" + }, + "references": [ + { + "path": "../circuits.js" + }, + { + "path": "../foundation" + }, + { + "path": "../types" + } + ], + "include": ["src", "src/**/*.json"] +} diff --git a/yarn-project/pxe/README.md b/yarn-project/pxe/README.md index bccdb05f11e..3cc76c41775 100644 --- a/yarn-project/pxe/README.md +++ b/yarn-project/pxe/README.md @@ -6,7 +6,7 @@ ### Main Components in an PXE Service -- [Acir Simulator](../acir-simulator/) +- [Simulator](../simulator/) - [Key Store](../key-store/) - [Account State](./src/account_state/account_state.ts): It coordinates other components to synchronize and decrypt data, simulate transactions, and generate kernel proofs, for a specific account. diff --git a/yarn-project/pxe/package.json b/yarn-project/pxe/package.json index 3ade258964c..75ba8afa0bd 100644 --- a/yarn-project/pxe/package.json +++ b/yarn-project/pxe/package.json @@ -33,7 +33,6 @@ "workerThreads": true }, "dependencies": { - "@aztec/acir-simulator": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/ethereum": "workspace:^", @@ -42,6 +41,8 @@ "@aztec/kv-store": "workspace:^", "@aztec/noir-compiler": "workspace:^", "@aztec/noir-protocol-circuits": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", + "@aztec/simulator": "workspace:^", "@aztec/types": "workspace:^", "koa": "^2.14.2", "koa-router": "^12.0.0", diff --git a/yarn-project/pxe/src/contract_data_oracle/index.ts b/yarn-project/pxe/src/contract_data_oracle/index.ts index a9617671959..0a2f6519524 100644 --- a/yarn-project/pxe/src/contract_data_oracle/index.ts +++ b/yarn-project/pxe/src/contract_data_oracle/index.ts @@ -1,4 +1,3 @@ -import { ContractClassNotFoundError, ContractNotFoundError } from '@aztec/acir-simulator'; import { ContractDatabase } from '@aztec/circuit-types'; import { AztecAddress, @@ -9,6 +8,7 @@ import { } from '@aztec/circuits.js'; import { FunctionDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; +import { ContractClassNotFoundError, ContractNotFoundError } from '@aztec/simulator'; import { ContractClass, ContractInstance } from '@aztec/types/contracts'; import { ContractArtifactDatabase } from '../database/contracts/contract_artifact_db.js'; diff --git a/yarn-project/pxe/src/database/kv_pxe_database.test.ts b/yarn-project/pxe/src/database/kv_pxe_database.test.ts index 27e0da25f37..501e8de9921 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.test.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.test.ts @@ -1,4 +1,4 @@ -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { KVPxeDatabase } from './kv_pxe_database.js'; import { describePxeDatabase } from './pxe_database_test_suite.js'; @@ -6,8 +6,8 @@ import { describePxeDatabase } from './pxe_database_test_suite.js'; describe('KVPxeDatabase', () => { let database: KVPxeDatabase; - beforeEach(async () => { - database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); + beforeEach(() => { + database = new KVPxeDatabase(openTmpStore()); }); describePxeDatabase(() => database); diff --git a/yarn-project/pxe/src/database/note_dao.ts b/yarn-project/pxe/src/database/note_dao.ts index 1a7e3442dcd..a8ae6e2e9f5 100644 --- a/yarn-project/pxe/src/database/note_dao.ts +++ b/yarn-project/pxe/src/database/note_dao.ts @@ -1,8 +1,8 @@ -import { NoteData } from '@aztec/acir-simulator'; import { Note, TxHash } from '@aztec/circuit-types'; import { AztecAddress, Fr, Point, PublicKey } from '@aztec/circuits.js'; import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; import { BufferReader } from '@aztec/foundation/serialize'; +import { NoteData } from '@aztec/simulator'; /** * A note with contextual data. diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 97bd4666009..a27752123a4 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -1,9 +1,9 @@ -import { ExecutionResult, NoteAndSlot } from '@aztec/acir-simulator'; import { FunctionL2Logs, Note } from '@aztec/circuit-types'; import { FunctionData, FunctionSelector, KernelCircuitPublicInputs, + KernelCircuitPublicInputsFinal, MAX_NEW_COMMITMENTS_PER_CALL, MAX_NEW_COMMITMENTS_PER_TX, MAX_READ_REQUESTS_PER_CALL, @@ -21,7 +21,7 @@ import { makeTxRequest } from '@aztec/circuits.js/factories'; import { makeTuple } from '@aztec/foundation/array'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; -import { Tuple } from '@aztec/foundation/serialize'; +import { ExecutionResult, NoteAndSlot } from '@aztec/simulator'; import { mock } from 'jest-mock-extended'; @@ -61,7 +61,7 @@ describe('Kernel Prover', () => { const functionData = FunctionData.empty(); functionData.selector = new FunctionSelector(fnName.charCodeAt(0)); return { - callStackItem: new PrivateCallStackItem(AztecAddress.ZERO, functionData, publicInputs, false), + callStackItem: new PrivateCallStackItem(AztecAddress.ZERO, functionData, publicInputs), nestedExecutions: (dependencies[fnName] || []).map(name => createExecutionResult(name)), vk: VerificationKey.makeFake().toBuffer(), newNotes: newNoteIndices.map(idx => notesAndSlots[idx]), @@ -81,11 +81,26 @@ describe('Kernel Prover', () => { const createProofOutput = (newNoteIndices: number[]) => { const publicInputs = KernelCircuitPublicInputs.empty(); - const commitments = newNoteIndices.map( - idx => new SideEffect(generateFakeSiloedCommitment(notesAndSlots[idx]), Fr.ZERO), - ); - // TODO(AD) FIXME(AD) This cast is bad. Why is this not the correct length when this is called? - publicInputs.end.newCommitments = commitments as Tuple; + const commitments = makeTuple(MAX_NEW_COMMITMENTS_PER_TX, () => SideEffect.empty()); + for (let i = 0; i < newNoteIndices.length; i++) { + commitments[i] = new SideEffect(generateFakeSiloedCommitment(notesAndSlots[newNoteIndices[i]]), Fr.ZERO); + } + + publicInputs.end.newCommitments = commitments; + return { + publicInputs, + proof: makeEmptyProof(), + }; + }; + + const createProofOutputFinal = (newNoteIndices: number[]) => { + const publicInputs = KernelCircuitPublicInputsFinal.empty(); + const commitments = makeTuple(MAX_NEW_COMMITMENTS_PER_TX, () => SideEffect.empty()); + for (let i = 0; i < newNoteIndices.length; i++) { + commitments[i] = new SideEffect(generateFakeSiloedCommitment(notesAndSlots[newNoteIndices[i]]), Fr.ZERO); + } + + publicInputs.end.newCommitments = commitments; return { publicInputs, proof: makeEmptyProof(), @@ -140,7 +155,7 @@ describe('Kernel Prover', () => { ); proofCreator.createProofInit.mockResolvedValue(createProofOutput([])); proofCreator.createProofInner.mockResolvedValue(createProofOutput([])); - proofCreator.createProofOrdering.mockResolvedValue(createProofOutput([])); + proofCreator.createProofOrdering.mockResolvedValue(createProofOutputFinal([])); prover = new KernelProver(oracle, proofCreator); }); @@ -182,7 +197,7 @@ describe('Kernel Prover', () => { proofCreator.createProofInit.mockResolvedValueOnce(createProofOutput([1, 2, 3])); proofCreator.createProofInner.mockResolvedValueOnce(createProofOutput([1, 3, 4])); proofCreator.createProofInner.mockResolvedValueOnce(createProofOutput([1, 3, 5, 6])); - proofCreator.createProofOrdering.mockResolvedValueOnce(createProofOutput([1, 3, 5, 6])); + proofCreator.createProofOrdering.mockResolvedValueOnce(createProofOutputFinal([1, 3, 5, 6])); const executionResult = { ...resultA, diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 9cf90394791..3977d4bf014 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -1,4 +1,3 @@ -import { ExecutionResult, NoteAndSlot } from '@aztec/acir-simulator'; import { AztecAddress, CallRequest, @@ -31,6 +30,7 @@ import { makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; import { Tuple, assertLength, mapTuple } from '@aztec/foundation/serialize'; import { pushTestData } from '@aztec/foundation/testing'; +import { ExecutionResult, NoteAndSlot } from '@aztec/simulator'; import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js'; import { ProvingDataOracle } from './proving_data_oracle.js'; diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 0b97ebf0326..a08189e5a21 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -1,4 +1,3 @@ -import { AcirSimulator } from '@aztec/acir-simulator'; import { AztecNode, FunctionL2Logs, @@ -17,7 +16,8 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Point } from '@aztec/foundation/fields'; import { ConstantKeyPair } from '@aztec/key-store'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; +import { AcirSimulator } from '@aztec/simulator'; import { jest } from '@jest/globals'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -118,8 +118,8 @@ describe('Note Processor', () => { owner = ConstantKeyPair.random(grumpkin); }); - beforeEach(async () => { - database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); + beforeEach(() => { + database = new KVPxeDatabase(openTmpStore()); addNotesSpy = jest.spyOn(database, 'addNotes'); aztecNode = mock(); diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index 0992685eaf1..4ed25627317 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -1,4 +1,3 @@ -import { ContractNotFoundError } from '@aztec/acir-simulator'; import { AztecNode, INITIAL_L2_BLOCK_NUM, @@ -13,6 +12,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { ContractNotFoundError } from '@aztec/simulator'; import { DeferredNoteDao } from '../database/deferred_note_dao.js'; import { PxeDatabase } from '../database/index.js'; diff --git a/yarn-project/pxe/src/note_processor/produce_note_dao.ts b/yarn-project/pxe/src/note_processor/produce_note_dao.ts index 14384dd6685..80a2bdbe1df 100644 --- a/yarn-project/pxe/src/note_processor/produce_note_dao.ts +++ b/yarn-project/pxe/src/note_processor/produce_note_dao.ts @@ -1,7 +1,7 @@ -import { AcirSimulator } from '@aztec/acir-simulator'; import { L1NotePayload, TxHash } from '@aztec/circuit-types'; import { Fr, PublicKey } from '@aztec/circuits.js'; import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis'; +import { AcirSimulator } from '@aztec/simulator'; import { NoteDao } from '../database/note_dao.js'; diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index 00d800f1e7a..d3b21dc5299 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -1,7 +1,10 @@ import { AztecNode } from '@aztec/circuit-types'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { TestKeyStore } from '@aztec/key-store'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { AztecLmdbStore } from '@aztec/kv-store/lmdb'; +import { initStoreForRollup } from '@aztec/kv-store/utils'; +import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer'; +import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer'; import { join } from 'path'; @@ -35,10 +38,14 @@ export async function createPXEService( const keyStorePath = config.dataDirectory ? join(config.dataDirectory, 'pxe_key_store') : undefined; const l1Contracts = await aztecNode.getL1ContractAddresses(); - const keyStore = new TestKeyStore(new Grumpkin(), await AztecLmdbStore.open(l1Contracts.rollupAddress, keyStorePath)); - const db = new KVPxeDatabase(await AztecLmdbStore.open(l1Contracts.rollupAddress, pxeDbPath)); + const keyStore = new TestKeyStore( + new Grumpkin(), + await initStoreForRollup(AztecLmdbStore.open(keyStorePath), l1Contracts.rollupAddress), + ); + const db = new KVPxeDatabase(await initStoreForRollup(AztecLmdbStore.open(pxeDbPath), l1Contracts.rollupAddress)); const server = new PXEService(keyStore, aztecNode, db, config, logSuffix); + await server.addContracts([getCanonicalClassRegisterer(), getCanonicalInstanceDeployer()]); await server.start(); return server; diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 09df2e57ebd..4b5b296aac0 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,11 +1,3 @@ -import { - AcirSimulator, - ExecutionResult, - collectEncryptedLogs, - collectEnqueuedPublicFunctionCalls, - collectUnencryptedLogs, - resolveOpcodeLocations, -} from '@aztec/acir-simulator'; import { AuthWitness, AztecNode, @@ -44,9 +36,9 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PartialAddress, PublicCallRequest, + computeArtifactHash, computeContractClassId, computeSaltedInitializationHash, - getArtifactHash, getContractClassFromArtifact, } from '@aztec/circuits.js'; import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/abis'; @@ -56,6 +48,14 @@ import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { + AcirSimulator, + ExecutionResult, + collectEncryptedLogs, + collectEnqueuedPublicFunctionCalls, + collectUnencryptedLogs, + resolveOpcodeLocations, +} from '@aztec/simulator'; import { ContractInstanceWithAddress } from '@aztec/types/contracts'; import { NodeInfo } from '@aztec/types/interfaces'; @@ -232,7 +232,7 @@ export class PXEService implements PXE { private async addArtifactsAndInstancesFromDeployedContracts(contracts: DeployedContract[]) { for (const contract of contracts) { const artifact = contract.artifact; - const artifactHash = getArtifactHash(artifact); + const artifactHash = computeArtifactHash(artifact); const contractClassId = computeContractClassId(getContractClassFromArtifact({ ...artifact, artifactHash })); await this.db.addContractArtifact(contractClassId, artifact); await this.db.addContractInstance(contract.instance); @@ -575,7 +575,7 @@ export class PXEService implements PXE { this.log('Executing unconstrained simulator...'); try { - const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress, this.node); + const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress); this.log('Unconstrained simulation completed!'); return result; diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 7caf5668e35..2258dca6566 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -3,7 +3,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { L1ContractAddresses } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; import { TestKeyStore } from '@aztec/key-store'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -13,8 +13,8 @@ import { PXEServiceConfig } from '../../index.js'; import { PXEService } from '../pxe_service.js'; import { pxeTestSuite } from './pxe_test_suite.js'; -async function createPXEService(): Promise { - const kvStore = await AztecLmdbStore.openTmp(); +function createPXEService(): Promise { + const kvStore = openTmpStore(); const keyStore = new TestKeyStore(new Grumpkin(), kvStore); const node = mock(); const db = new KVPxeDatabase(kvStore); @@ -45,8 +45,8 @@ describe('PXEService', () => { let db: PxeDatabase; let config: PXEServiceConfig; - beforeEach(async () => { - const kvStore = await AztecLmdbStore.openTmp(); + beforeEach(() => { + const kvStore = openTmpStore(); keyStore = new TestKeyStore(new Grumpkin(), kvStore); node = mock(); db = new KVPxeDatabase(kvStore); diff --git a/yarn-project/pxe/src/simulator/index.ts b/yarn-project/pxe/src/simulator/index.ts index 090acd2f5d2..40d30a9198d 100644 --- a/yarn-project/pxe/src/simulator/index.ts +++ b/yarn-project/pxe/src/simulator/index.ts @@ -1,5 +1,5 @@ -import { AcirSimulator } from '@aztec/acir-simulator'; -import { KeyStore, StateInfoProvider } from '@aztec/circuit-types'; +import { AztecNode, KeyStore } from '@aztec/circuit-types'; +import { AcirSimulator } from '@aztec/simulator'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { PxeDatabase } from '../database/pxe_database.js'; @@ -10,7 +10,7 @@ import { SimulatorOracle } from '../simulator_oracle/index.js'; */ export function getAcirSimulator( db: PxeDatabase, - stateInfoProvider: StateInfoProvider, + aztecNode: AztecNode, keyStore: KeyStore, contractDataOracle?: ContractDataOracle, ) { @@ -18,7 +18,7 @@ export function getAcirSimulator( contractDataOracle ?? new ContractDataOracle(db), db, keyStore, - stateInfoProvider, + aztecNode, ); - return new AcirSimulator(simulatorOracle); + return new AcirSimulator(simulatorOracle, aztecNode); } diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 24e5f2208b3..8856cbeb205 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -1,12 +1,11 @@ -import { DBOracle, KeyPair, MessageLoadOracleInputs } from '@aztec/acir-simulator'; import { + AztecNode, KeyStore, L2Block, MerkleTreeId, NoteStatus, NullifierMembershipWitness, PublicDataWitness, - StateInfoProvider, } from '@aztec/circuit-types'; import { AztecAddress, @@ -19,6 +18,7 @@ import { } from '@aztec/circuits.js'; import { FunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; +import { DBOracle, KeyPair, MessageLoadOracleInputs } from '@aztec/simulator'; import { ContractDataOracle } from '../contract_data_oracle/index.js'; import { PxeDatabase } from '../database/index.js'; @@ -31,7 +31,7 @@ export class SimulatorOracle implements DBOracle { private contractDataOracle: ContractDataOracle, private db: PxeDatabase, private keyStore: KeyStore, - private stateInfoProvider: StateInfoProvider, + private aztecNode: AztecNode, private log = createDebugLogger('aztec:pxe:simulator_oracle'), ) {} @@ -127,10 +127,10 @@ export class SimulatorOracle implements DBOracle { * index of the message in the l1ToL2MessageTree */ async getL1ToL2Message(msgKey: Fr): Promise> { - const messageAndIndex = await this.stateInfoProvider.getL1ToL2MessageAndIndex(msgKey); + const messageAndIndex = await this.aztecNode.getL1ToL2MessageAndIndex(msgKey); const message = messageAndIndex.message; const index = messageAndIndex.index; - const siblingPath = await this.stateInfoProvider.getL1ToL2MessageSiblingPath('latest', index); + const siblingPath = await this.aztecNode.getL1ToL2MessageSiblingPath('latest', index); return new MessageLoadOracleInputs(message, index, siblingPath); } @@ -140,30 +140,29 @@ export class SimulatorOracle implements DBOracle { * @returns - The index of the commitment. Undefined if it does not exist in the tree. */ async getCommitmentIndex(commitment: Fr) { - return await this.stateInfoProvider.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment); + return await this.aztecNode.findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment); } async getNullifierIndex(nullifier: Fr) { - return await this.stateInfoProvider.findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier); + return await this.aztecNode.findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier); } public async findLeafIndex(blockNumber: number, treeId: MerkleTreeId, leafValue: Fr): Promise { - return await this.stateInfoProvider.findLeafIndex(blockNumber, treeId, leafValue); + return await this.aztecNode.findLeafIndex(blockNumber, treeId, leafValue); } public async getSiblingPath(blockNumber: number, treeId: MerkleTreeId, leafIndex: bigint): Promise { - // @todo Doing a nasty workaround here because of https://github.com/AztecProtocol/aztec-packages/issues/3414 switch (treeId) { case MerkleTreeId.CONTRACT_TREE: - return (await this.stateInfoProvider.getContractSiblingPath(blockNumber, leafIndex)).toFields(); + return (await this.aztecNode.getContractSiblingPath(blockNumber, leafIndex)).toFields(); case MerkleTreeId.NULLIFIER_TREE: - return (await this.stateInfoProvider.getNullifierSiblingPath(blockNumber, leafIndex)).toFields(); + return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields(); case MerkleTreeId.NOTE_HASH_TREE: - return (await this.stateInfoProvider.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields(); + return (await this.aztecNode.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields(); case MerkleTreeId.PUBLIC_DATA_TREE: - return (await this.stateInfoProvider.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields(); + return (await this.aztecNode.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields(); case MerkleTreeId.ARCHIVE: - return (await this.stateInfoProvider.getArchiveSiblingPath(blockNumber, leafIndex)).toFields(); + return (await this.aztecNode.getArchiveSiblingPath(blockNumber, leafIndex)).toFields(); default: throw new Error('Not implemented'); } @@ -173,22 +172,22 @@ export class SimulatorOracle implements DBOracle { blockNumber: number, nullifier: Fr, ): Promise { - return this.stateInfoProvider.getNullifierMembershipWitness(blockNumber, nullifier); + return this.aztecNode.getNullifierMembershipWitness(blockNumber, nullifier); } public getLowNullifierMembershipWitness( blockNumber: number, nullifier: Fr, ): Promise { - return this.stateInfoProvider.getLowNullifierMembershipWitness(blockNumber, nullifier); + return this.aztecNode.getLowNullifierMembershipWitness(blockNumber, nullifier); } public async getBlock(blockNumber: number): Promise { - return await this.stateInfoProvider.getBlock(blockNumber); + return await this.aztecNode.getBlock(blockNumber); } public async getPublicDataTreeWitness(blockNumber: number, leafSlot: Fr): Promise { - return await this.stateInfoProvider.getPublicDataTreeWitness(blockNumber, leafSlot); + return await this.aztecNode.getPublicDataTreeWitness(blockNumber, leafSlot); } /** @@ -206,6 +205,6 @@ export class SimulatorOracle implements DBOracle { * @returns The block number. */ public async getBlockNumber(): Promise { - return await this.stateInfoProvider.getBlockNumber(); + return await this.aztecNode.getBlockNumber(); } } diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index aa283ba1bec..4353ba36b9b 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -4,7 +4,7 @@ import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { makeHeader } from '@aztec/circuits.js/factories'; import { SerialQueue } from '@aztec/foundation/fifo'; import { TestKeyStore } from '@aztec/key-store'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { MockProxy, mock } from 'jest-mock-extended'; import omit from 'lodash.omit'; @@ -21,11 +21,11 @@ describe('Synchronizer', () => { const initialSyncBlockNumber = 3; let headerBlock3: Header; - beforeEach(async () => { + beforeEach(() => { headerBlock3 = makeHeader(Math.floor(Math.random() * 1000), initialSyncBlockNumber); aztecNode = mock(); - database = new KVPxeDatabase(await AztecLmdbStore.openTmp()); + database = new KVPxeDatabase(openTmpStore()); jobQueue = new SerialQueue(); synchronizer = new TestSynchronizer(aztecNode, database, jobQueue); }); @@ -114,7 +114,7 @@ describe('Synchronizer', () => { expect(await synchronizer.isGlobalStateSynchronized()).toBe(true); // Manually adding account to database so that we can call synchronizer.isAccountStateSynchronized - const keyStore = new TestKeyStore(new Grumpkin(), await AztecLmdbStore.openTmp()); + const keyStore = new TestKeyStore(new Grumpkin(), openTmpStore()); const addAddress = async (startingBlockNum: number) => { const privateKey = GrumpkinScalar.random(); await keyStore.addAccount(privateKey); diff --git a/yarn-project/pxe/tsconfig.json b/yarn-project/pxe/tsconfig.json index 4af0483e9f2..91273923e82 100644 --- a/yarn-project/pxe/tsconfig.json +++ b/yarn-project/pxe/tsconfig.json @@ -7,7 +7,7 @@ }, "references": [ { - "path": "../acir-simulator" + "path": "../simulator" }, { "path": "../circuit-types" @@ -33,6 +33,9 @@ { "path": "../noir-protocol-circuits" }, + { + "path": "../protocol-contracts" + }, { "path": "../types" }, diff --git a/yarn-project/sequencer-client/package.json b/yarn-project/sequencer-client/package.json index 40bf5fd98ee..22a1bb28a40 100644 --- a/yarn-project/sequencer-client/package.json +++ b/yarn-project/sequencer-client/package.json @@ -32,7 +32,6 @@ "rootDir": "./src" }, "dependencies": { - "@aztec/acir-simulator": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/ethereum": "workspace:^", @@ -41,6 +40,7 @@ "@aztec/merkle-tree": "workspace:^", "@aztec/noir-protocol-circuits": "workspace:^", "@aztec/p2p": "workspace:^", + "@aztec/simulator": "workspace:^", "@aztec/types": "workspace:^", "@aztec/world-state": "workspace:^", "lodash.chunk": "^4.2.0", diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts index 470ce36f9cc..06e160d99f2 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.test.ts @@ -12,7 +12,9 @@ import { } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, + AztecAddress, BaseOrMergeRollupPublicInputs, + EthAddress, Fr, GlobalVariables, Header, @@ -50,7 +52,7 @@ import { makeTuple, range } from '@aztec/foundation/array'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { times } from '@aztec/foundation/collection'; import { to2Fields } from '@aztec/foundation/serialize'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -91,13 +93,15 @@ describe('sequencer/solo_block_builder', () => { const chainId = Fr.ZERO; const version = Fr.ZERO; + const coinbase = EthAddress.ZERO; + const feeRecipient = AztecAddress.ZERO; beforeEach(async () => { blockNumber = 3; - globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO); + globalVariables = new GlobalVariables(chainId, version, new Fr(blockNumber), Fr.ZERO, coinbase, feeRecipient); - builderDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); - expectsDb = await MerkleTrees.new(await AztecLmdbStore.openTmp()).then(t => t.asLatest()); + builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); + expectsDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); vks = getVerificationKeys(); simulator = mock(); prover = mock(); diff --git a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts index 43d764001bc..a421440cc9c 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -358,9 +358,7 @@ export class SoloBlockBuilder implements BlockBuilder { ]; const getRootTreeSiblingPath = async (treeId: MerkleTreeId) => { - // TODO: Synchronize these operations into the tree db to avoid race conditions const { size } = await this.db.getTreeInfo(treeId); - // TODO: Check for off-by-one errors const path = await this.db.getSiblingPath(treeId, size); return path.toFields(); }; diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index 90a3003f5b7..242221f3f5e 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -86,4 +86,12 @@ export class SequencerClient { public restart() { this.sequencer.restart(); } + + get coinbase() { + return this.sequencer.coinbase; + } + + get feeRecipient() { + return this.sequencer.feeRecipient; + } } diff --git a/yarn-project/sequencer-client/src/config.ts b/yarn-project/sequencer-client/src/config.ts index ee407d8410a..43bfa76a175 100644 --- a/yarn-project/sequencer-client/src/config.ts +++ b/yarn-project/sequencer-client/src/config.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/circuits.js'; import { L1ContractAddresses, NULL_KEY } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -45,6 +46,8 @@ export function getConfigEnvVars(): SequencerClientConfig { INBOX_CONTRACT_ADDRESS, CONTRACT_DEPLOYMENT_EMITTER_ADDRESS, OUTBOX_CONTRACT_ADDRESS, + COINBASE, + FEE_RECIPIENT, } = process.env; const publisherPrivateKey: Hex = SEQ_PUBLISHER_PRIVATE_KEY @@ -76,5 +79,8 @@ export function getConfigEnvVars(): SequencerClientConfig { publisherPrivateKey, maxTxsPerBlock: SEQ_MAX_TX_PER_BLOCK ? +SEQ_MAX_TX_PER_BLOCK : 32, minTxsPerBlock: SEQ_MIN_TX_PER_BLOCK ? +SEQ_MIN_TX_PER_BLOCK : 1, + // TODO: undefined should not be allowed for the following 2 values in PROD + coinbase: COINBASE ? EthAddress.fromString(COINBASE) : undefined, + feeRecipient: FEE_RECIPIENT ? AztecAddress.fromString(FEE_RECIPIENT) : undefined, }; } diff --git a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts index d50a8b8f83b..2b6212b71da 100644 --- a/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts +++ b/yarn-project/sequencer-client/src/global_variable_builder/global_builder.ts @@ -1,4 +1,4 @@ -import { GlobalVariables } from '@aztec/circuits.js'; +import { AztecAddress, EthAddress, GlobalVariables } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -42,9 +42,11 @@ export interface GlobalVariableBuilder { /** * Builds global variables. * @param blockNumber - The block number to build global variables for. + * @param coinbase - The address to receive block reward. + * @param feeRecipient - The address to receive fees. * @returns The global variables for the given block number. */ - buildGlobalVariables(blockNumber: Fr): Promise; + buildGlobalVariables(blockNumber: Fr, coinbase: EthAddress, feeRecipient: AztecAddress): Promise; } /** @@ -58,9 +60,15 @@ export class SimpleTestGlobalVariableBuilder implements GlobalVariableBuilder { /** * Simple builder of global variables that use the minimum time possible. * @param blockNumber - The block number to build global variables for. + * @param coinbase - The address to receive block reward. + * @param feeRecipient - The address to receive fees. * @returns The global variables for the given block number. */ - public async buildGlobalVariables(blockNumber: Fr): Promise { + public async buildGlobalVariables( + blockNumber: Fr, + coinbase: EthAddress, + feeRecipient: AztecAddress, + ): Promise { let lastTimestamp = new Fr(await this.reader.getLastTimestamp()); const version = new Fr(await this.reader.getVersion()); const chainId = new Fr(await this.reader.getChainId()); @@ -79,9 +87,9 @@ export class SimpleTestGlobalVariableBuilder implements GlobalVariableBuilder { } this.log( - `Built global variables for block ${blockNumber}: (${chainId}, ${version}, ${blockNumber}, ${lastTimestamp})`, + `Built global variables for block ${blockNumber}: (${chainId}, ${version}, ${blockNumber}, ${lastTimestamp}, ${coinbase}, ${feeRecipient})`, ); - return new GlobalVariables(chainId, version, blockNumber, lastTimestamp); + return new GlobalVariables(chainId, version, blockNumber, lastTimestamp, coinbase, feeRecipient); } } diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index 94e0dc7b9f1..abedccab59f 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -1,11 +1,3 @@ -import { - PublicExecution, - PublicExecutionResult, - PublicExecutor, - collectPublicDataReads, - collectPublicDataUpdateRequests, - isPublicExecutionResult, -} from '@aztec/acir-simulator'; import { FunctionL2Logs, MerkleTreeId, Tx } from '@aztec/circuit-types'; import { AztecAddress, @@ -45,6 +37,14 @@ import { computeVarArgsHash } from '@aztec/circuits.js/abis'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; import { to2Fields } from '@aztec/foundation/serialize'; +import { + PublicExecution, + PublicExecutionResult, + PublicExecutor, + collectPublicDataReads, + collectPublicDataUpdateRequests, + isPublicExecutionResult, +} from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; import { getVerificationKeys } from '../mocks/verification_keys.js'; @@ -117,6 +117,8 @@ export abstract class AbstractPhaseManager { }; } else { const publicKernelOutput = new KernelCircuitPublicInputs( + tx.data.aggregationObject, + tx.data.metaHwm, CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), tx.data.constants, tx.data.isPrivate, diff --git a/yarn-project/sequencer-client/src/sequencer/application_logic_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/application_logic_phase_manager.ts index 18a0ec368d3..12d147ab9c1 100644 --- a/yarn-project/sequencer-client/src/sequencer/application_logic_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/application_logic_phase_manager.ts @@ -1,8 +1,8 @@ -import { PublicExecutor, PublicStateDB } from '@aztec/acir-simulator'; import { Tx } from '@aztec/circuit-types'; import { GlobalVariables, Header, Proof, PublicCallRequest, PublicKernelPublicInputs } from '@aztec/circuits.js'; import { isArrayEmpty } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; +import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; import { PublicProver } from '../prover/index.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/fee_distribution_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/fee_distribution_phase_manager.ts index 50cea90b51e..b90bc544b6b 100644 --- a/yarn-project/sequencer-client/src/sequencer/fee_distribution_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/fee_distribution_phase_manager.ts @@ -1,7 +1,7 @@ -import { PublicExecutor, PublicStateDB } from '@aztec/acir-simulator'; import { Tx } from '@aztec/circuit-types'; import { GlobalVariables, Header, Proof, PublicCallRequest, PublicKernelPublicInputs } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; +import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; import { PublicProver } from '../prover/index.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/fee_preparation_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/fee_preparation_phase_manager.ts index 48e225be8a8..7923ea8cbfc 100644 --- a/yarn-project/sequencer-client/src/sequencer/fee_preparation_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/fee_preparation_phase_manager.ts @@ -1,7 +1,7 @@ -import { PublicExecutor, PublicStateDB } from '@aztec/acir-simulator'; import { Tx } from '@aztec/circuit-types'; import { GlobalVariables, Header, Proof, PublicCallRequest, PublicKernelPublicInputs } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; +import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; import { PublicProver } from '../prover/index.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 342e7f834ba..ecf299b9b68 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -56,7 +56,12 @@ export async function makeProcessedTx( hash: await tx.getTxHash(), data: kernelOutput ?? - new PublicKernelPublicInputs(CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), tx.data.constants), + new PublicKernelPublicInputs( + tx.data.aggregationObject, + tx.data.metaHwm, + CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), + tx.data.constants, + ), proof: proof ?? tx.proof, encryptedLogs: tx.encryptedLogs, unencryptedLogs: tx.unencryptedLogs, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 89d30f0c393..dfa2fa4821b 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -1,4 +1,3 @@ -import { PublicExecution, PublicExecutionResult, PublicExecutor } from '@aztec/acir-simulator'; import { ExtendedContractData, FunctionCall, @@ -36,6 +35,7 @@ import { } from '@aztec/circuits.js/factories'; import { makeTuple } from '@aztec/foundation/array'; import { padArrayEnd, times } from '@aztec/foundation/collection'; +import { PublicExecution, PublicExecutionResult, PublicExecutor } from '@aztec/simulator'; import { MerkleTreeOperations, TreeInfo } from '@aztec/world-state'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -101,6 +101,8 @@ describe('public_processor', () => { isEmpty: false, hash, data: new PublicKernelPublicInputs( + tx.data.aggregationObject, + tx.data.metaHwm, CombinedAccumulatedData.fromFinalAccumulatedData(tx.data.end), tx.data.constants, ), diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index de452d51c98..aa85da97d64 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -1,9 +1,9 @@ -import { PublicExecutor, PublicStateDB } from '@aztec/acir-simulator'; import { ContractDataSource, L1ToL2MessageSource, Tx } from '@aztec/circuit-types'; import { TxSequencerProcessingStats } from '@aztec/circuit-types/stats'; import { GlobalVariables, Header, Proof, PublicKernelPublicInputs } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { PublicExecutor, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; import { EmptyPublicProver } from '../prover/empty.js'; diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index f3d94763f0e..dc433041bb5 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -8,7 +8,15 @@ import { TxHash, mockTx, } from '@aztec/circuit-types'; -import { Fr, GlobalVariables, Header, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, makeEmptyProof } from '@aztec/circuits.js'; +import { + AztecAddress, + EthAddress, + Fr, + GlobalVariables, + Header, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, + makeEmptyProof, +} from '@aztec/circuits.js'; import { times } from '@aztec/foundation/collection'; import { P2P, P2PClientState } from '@aztec/p2p'; import { MerkleTreeOperations, WorldStateRunningState, WorldStateSynchronizer } from '@aztec/world-state'; @@ -40,6 +48,8 @@ describe('sequencer', () => { const chainId = new Fr(12345); const version = Fr.ZERO; + const coinbase = EthAddress.random(); + const feeRecipient = AztecAddress.random(); beforeEach(() => { lastBlockNumber = 0; @@ -98,7 +108,7 @@ describe('sequencer', () => { blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), ); await sequencer.initialSync(); @@ -107,7 +117,7 @@ describe('sequencer', () => { const expectedTxHashes = [...(await Tx.getHashes([tx])), ...times(1, () => TxHash.ZERO)]; expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); @@ -127,7 +137,7 @@ describe('sequencer', () => { blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), ); // We make a nullifier from tx1 a part of the nullifier tree, so it gets rejected as double spend @@ -144,7 +154,7 @@ describe('sequencer', () => { const expectedTxHashes = await Tx.getHashes([txs[0], txs[2]]); expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); @@ -165,7 +175,7 @@ describe('sequencer', () => { blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), ); // We make the chain id on the invalid tx not equal to the configured chain id @@ -177,7 +187,7 @@ describe('sequencer', () => { const expectedTxHashes = await Tx.getHashes([txs[0], txs[2]]); expect(blockBuilder.buildL2Block).toHaveBeenCalledWith( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), expectedTxHashes.map(hash => expect.objectContaining({ hash })), Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); @@ -195,7 +205,7 @@ describe('sequencer', () => { blockBuilder.buildL2Block.mockResolvedValueOnce([block, proof]); publisher.processL2Block.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), ); await sequencer.initialSync(); @@ -230,7 +240,7 @@ describe('sequencer', () => { publisher.processL2Block.mockResolvedValueOnce(true); publisher.processNewContractData.mockResolvedValueOnce(true); globalVariableBuilder.buildGlobalVariables.mockResolvedValueOnce( - new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO), + new GlobalVariables(chainId, version, new Fr(lastBlockNumber + 1), Fr.ZERO, coinbase, feeRecipient), ); await sequencer.initialSync(); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index ca31b58d3b5..da7df333d2d 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -1,6 +1,6 @@ import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, Tx } from '@aztec/circuit-types'; import { L2BlockBuiltStats } from '@aztec/circuit-types/stats'; -import { GlobalVariables } from '@aztec/circuits.js'; +import { AztecAddress, EthAddress, GlobalVariables } from '@aztec/circuits.js'; import { times } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -31,6 +31,9 @@ export class Sequencer { private pollingIntervalMs: number = 1000; private maxTxsPerBlock = 32; private minTxsPerBLock = 1; + // TODO: zero values should not be allowed for the following 2 values in PROD + private _coinbase = EthAddress.ZERO; + private _feeRecipient = AztecAddress.ZERO; private lastPublishedBlock = 0; private state = SequencerState.STOPPED; @@ -64,6 +67,12 @@ export class Sequencer { if (config.minTxsPerBlock) { this.minTxsPerBLock = config.minTxsPerBlock; } + if (config.coinbase) { + this._coinbase = config.coinbase; + } + if (config.feeRecipient) { + this._feeRecipient = config.feeRecipient; + } } /** @@ -155,7 +164,11 @@ export class Sequencer { } }; - const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables(new Fr(newBlockNumber)); + const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables( + new Fr(newBlockNumber), + this._coinbase, + this._feeRecipient, + ); // Filter out invalid txs // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here @@ -408,6 +421,14 @@ export class Sequencer { } return false; } + + get coinbase(): EthAddress { + return this._coinbase; + } + + get feeRecipient(): AztecAddress { + return this._feeRecipient; + } } /** diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 7ee16c8e0bd..5d9ac0cd000 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -1,4 +1,3 @@ -import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/acir-simulator'; import { ContractDataSource, ExtendedContractData, L1ToL2MessageSource, MerkleTreeId, Tx } from '@aztec/circuit-types'; import { AztecAddress, @@ -9,6 +8,7 @@ import { PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/abis'; +import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; import { MerkleTreeOperations } from '@aztec/world-state'; /** diff --git a/yarn-project/sequencer-client/tsconfig.json b/yarn-project/sequencer-client/tsconfig.json index 7a1f29b1488..d17fa6334ab 100644 --- a/yarn-project/sequencer-client/tsconfig.json +++ b/yarn-project/sequencer-client/tsconfig.json @@ -7,7 +7,7 @@ }, "references": [ { - "path": "../acir-simulator" + "path": "../simulator" }, { "path": "../circuit-types" diff --git a/yarn-project/simulator/.eslintrc.cjs b/yarn-project/simulator/.eslintrc.cjs new file mode 100644 index 00000000000..e659927475c --- /dev/null +++ b/yarn-project/simulator/.eslintrc.cjs @@ -0,0 +1 @@ +module.exports = require('@aztec/foundation/eslint'); diff --git a/yarn-project/acir-simulator/README.md b/yarn-project/simulator/README.md similarity index 98% rename from yarn-project/acir-simulator/README.md rename to yarn-project/simulator/README.md index bc61142d327..41b8fe31baf 100644 --- a/yarn-project/acir-simulator/README.md +++ b/yarn-project/simulator/README.md @@ -1,8 +1,8 @@ -# ACIR Simulator +# Simulator ## Responsibilities -This library package is responsible for simulating function circuits compiled to ACIR. +This library package is responsible for simulating function circuits compiled to ACIR / AVM. Simulating a function implies generating the partial witness and the public inputs of the function, as well as collecting all the data (such as created notes or nullifiers, or state changes) that are necessary for components upstream. diff --git a/yarn-project/acir-simulator/package.json b/yarn-project/simulator/package.json similarity index 93% rename from yarn-project/acir-simulator/package.json rename to yarn-project/simulator/package.json index ccd51b8ba54..0a84d51627b 100644 --- a/yarn-project/acir-simulator/package.json +++ b/yarn-project/simulator/package.json @@ -1,5 +1,5 @@ { - "name": "@aztec/acir-simulator", + "name": "@aztec/simulator", "version": "0.1.0", "type": "module", "exports": "./dest/index.js", @@ -7,7 +7,7 @@ "entryPoints": [ "./src/index.ts" ], - "name": "Acir Simulator", + "name": "Simulator", "tsconfig": "./tsconfig.json" }, "scripts": { @@ -45,10 +45,12 @@ "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", "@types/levelup": "^5.1.3", + "@types/lodash.merge": "^4.6.9", "@types/memdown": "^3.0.2", "@types/node": "^18.7.23", "jest": "^29.5.0", "jest-mock-extended": "^3.0.4", + "lodash.merge": "^4.6.2", "ts-jest": "^29.1.0", "ts-node": "^10.9.1", "typescript": "^5.0.4", diff --git a/yarn-project/acir-simulator/src/acvm/acvm.ts b/yarn-project/simulator/src/acvm/acvm.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/acvm.ts rename to yarn-project/simulator/src/acvm/acvm.ts diff --git a/yarn-project/acir-simulator/src/acvm/acvm_types.ts b/yarn-project/simulator/src/acvm/acvm_types.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/acvm_types.ts rename to yarn-project/simulator/src/acvm/acvm_types.ts diff --git a/yarn-project/acir-simulator/src/acvm/deserialize.ts b/yarn-project/simulator/src/acvm/deserialize.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/deserialize.ts rename to yarn-project/simulator/src/acvm/deserialize.ts diff --git a/yarn-project/acir-simulator/src/acvm/index.ts b/yarn-project/simulator/src/acvm/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/index.ts rename to yarn-project/simulator/src/acvm/index.ts diff --git a/yarn-project/acir-simulator/src/acvm/oracle/debug.ts b/yarn-project/simulator/src/acvm/oracle/debug.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/oracle/debug.ts rename to yarn-project/simulator/src/acvm/oracle/debug.ts diff --git a/yarn-project/acir-simulator/src/acvm/oracle/index.ts b/yarn-project/simulator/src/acvm/oracle/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/oracle/index.ts rename to yarn-project/simulator/src/acvm/oracle/index.ts diff --git a/yarn-project/acir-simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/oracle/oracle.ts rename to yarn-project/simulator/src/acvm/oracle/oracle.ts diff --git a/yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts similarity index 100% rename from yarn-project/acir-simulator/src/acvm/oracle/typed_oracle.ts rename to yarn-project/simulator/src/acvm/oracle/typed_oracle.ts diff --git a/yarn-project/acir-simulator/src/acvm/serialize.ts b/yarn-project/simulator/src/acvm/serialize.ts similarity index 97% rename from yarn-project/acir-simulator/src/acvm/serialize.ts rename to yarn-project/simulator/src/acvm/serialize.ts index 28ca4b3e27f..1ddcf1ea98d 100644 --- a/yarn-project/acir-simulator/src/acvm/serialize.ts +++ b/yarn-project/simulator/src/acvm/serialize.ts @@ -50,6 +50,7 @@ export function toACVMField( * are empty since this is just an execution request, so we don't send them to the circuit. * @param item - The public call stack item to serialize to be passed onto Noir. * @returns The fields expected by the enqueue_public_function_call_oracle Aztec.nr function. + * TODO(#4380): Nuke this and replace it with PublicCallRequest.toFields() */ export function toAcvmEnqueuePublicFunctionResult(item: PublicCallRequest): ACVMField[] { return [ diff --git a/yarn-project/simulator/src/avm/avm_context.test.ts b/yarn-project/simulator/src/avm/avm_context.test.ts new file mode 100644 index 00000000000..240de5eb14f --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_context.test.ts @@ -0,0 +1,57 @@ +import { AztecAddress, Fr } from '@aztec/circuits.js'; + +import { allSameExcept, initContext } from './fixtures/index.js'; + +describe('Avm Context', () => { + it('New call should fork context correctly', () => { + const context = initContext(); + context.machineState.pc = 20; + + const newAddress = AztecAddress.random(); + const newCalldata = [new Fr(1), new Fr(2)]; + const newContext = context.createNestedContractCallContext(newAddress, newCalldata); + + expect(newContext.environment).toEqual( + allSameExcept(context.environment, { + address: newAddress, + storageAddress: newAddress, + calldata: newCalldata, + isStaticCall: false, + }), + ); + expect(newContext.machineState).toEqual( + allSameExcept(context.machineState, { + pc: 0, + }), + ); + + // We stringify to remove circular references (parentJournal) + expect(JSON.stringify(newContext.worldState)).toEqual(JSON.stringify(context.worldState.fork())); + }); + + it('New static call should fork context correctly', () => { + const context = initContext(); + context.machineState.pc = 20; + + const newAddress = AztecAddress.random(); + const newCalldata = [new Fr(1), new Fr(2)]; + const newContext = context.createNestedContractStaticCallContext(newAddress, newCalldata); + + expect(newContext.environment).toEqual( + allSameExcept(context.environment, { + address: newAddress, + storageAddress: newAddress, + calldata: newCalldata, + isStaticCall: true, + }), + ); + expect(newContext.machineState).toEqual( + allSameExcept(context.machineState, { + pc: 0, + }), + ); + + // We stringify to remove circular references (parentJournal) + expect(JSON.stringify(newContext.worldState)).toEqual(JSON.stringify(context.worldState.fork())); + }); +}); diff --git a/yarn-project/simulator/src/avm/avm_context.ts b/yarn-project/simulator/src/avm/avm_context.ts new file mode 100644 index 00000000000..851f4bfc536 --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_context.ts @@ -0,0 +1,63 @@ +import { AztecAddress } from '@aztec/circuits.js'; +import { Fr } from '@aztec/foundation/fields'; + +import { AvmExecutionEnvironment } from './avm_execution_environment.js'; +import { AvmMachineState } from './avm_machine_state.js'; +import { AvmWorldStateJournal } from './journal/journal.js'; + +/** + * An execution context includes the information necessary to initiate AVM + * execution along with all state maintained by the AVM throughout execution. + */ +export class AvmContext { + /** + * Create a new AVM context + * @param worldState - Manages mutable state during execution - (caching, fetching) + * @param environment - Contains constant variables provided by the kernel + * @param machineState - VM state that is modified on an instruction-by-instruction basis + * @returns new AvmContext instance + */ + constructor( + public worldState: AvmWorldStateJournal, + public environment: AvmExecutionEnvironment, + public machineState: AvmMachineState, + ) {} + + /** + * Prepare a new AVM context that will be ready for an external/nested call + * - Fork the world state journal + * - Derive a machine state from the current state + * - E.g., gas metering is preserved but pc is reset + * - Derive an execution environment from the caller/parent + * - Alter both address and storageAddress + * + * @param address - The contract instance to initialize a context for + * @param calldata - Data/arguments for nested call + * @returns new AvmContext instance + */ + public createNestedContractCallContext(address: AztecAddress, calldata: Fr[]): AvmContext { + const newExecutionEnvironment = this.environment.deriveEnvironmentForNestedCall(address, calldata); + const forkedWorldState = this.worldState.fork(); + const machineState = AvmMachineState.fromState(this.machineState); + return new AvmContext(forkedWorldState, newExecutionEnvironment, machineState); + } + + /** + * Prepare a new AVM context that will be ready for an external/nested static call + * - Fork the world state journal + * - Derive a machine state from the current state + * - E.g., gas metering is preserved but pc is reset + * - Derive an execution environment from the caller/parent + * - Alter both address and storageAddress + * + * @param address - The contract instance to initialize a context for + * @param calldata - Data/arguments for nested call + * @returns new AvmContext instance + */ + public createNestedContractStaticCallContext(address: AztecAddress, calldata: Fr[]): AvmContext { + const newExecutionEnvironment = this.environment.deriveEnvironmentForNestedStaticCall(address, calldata); + const forkedWorldState = this.worldState.fork(); + const machineState = AvmMachineState.fromState(this.machineState); + return new AvmContext(forkedWorldState, newExecutionEnvironment, machineState); + } +} diff --git a/yarn-project/simulator/src/avm/avm_execution_environment.test.ts b/yarn-project/simulator/src/avm/avm_execution_environment.test.ts new file mode 100644 index 00000000000..e2104cbad59 --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_execution_environment.test.ts @@ -0,0 +1,48 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { allSameExcept, initExecutionEnvironment } from './fixtures/index.js'; + +describe('Execution Environment', () => { + const newAddress = new Fr(123456n); + const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; + + it('New call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedCall(newAddress, calldata); + + expect(newExecutionEnvironment).toEqual( + allSameExcept(executionEnvironment, { + address: newAddress, + storageAddress: newAddress, + calldata, + }), + ); + }); + + it('New delegate call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.newDelegateCall(newAddress, calldata); + + expect(newExecutionEnvironment).toEqual( + allSameExcept(executionEnvironment, { + address: newAddress, + isDelegateCall: true, + calldata, + }), + ); + }); + + it('New static call call should fork execution environment correctly', () => { + const executionEnvironment = initExecutionEnvironment(); + const newExecutionEnvironment = executionEnvironment.deriveEnvironmentForNestedStaticCall(newAddress, calldata); + + expect(newExecutionEnvironment).toEqual( + allSameExcept(executionEnvironment, { + address: newAddress, + storageAddress: newAddress, + isStaticCall: true, + calldata, + }), + ); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts b/yarn-project/simulator/src/avm/avm_execution_environment.ts similarity index 91% rename from yarn-project/acir-simulator/src/avm/avm_execution_environment.ts rename to yarn-project/simulator/src/avm/avm_execution_environment.ts index 6a87f62d87b..aa3bbb4672c 100644 --- a/yarn-project/acir-simulator/src/avm/avm_execution_environment.ts +++ b/yarn-project/simulator/src/avm/avm_execution_environment.ts @@ -37,7 +37,7 @@ export class AvmExecutionEnvironment { public readonly calldata: Fr[], ) {} - public newCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { + public deriveEnvironmentForNestedCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { return new AvmExecutionEnvironment( /*address=*/ address, /*storageAddress=*/ address, @@ -55,7 +55,7 @@ export class AvmExecutionEnvironment { ); } - public newStaticCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { + public deriveEnvironmentForNestedStaticCall(address: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment { return new AvmExecutionEnvironment( /*address=*/ address, /*storageAddress=*/ address, diff --git a/yarn-project/simulator/src/avm/avm_machine_state.ts b/yarn-project/simulator/src/avm/avm_machine_state.ts new file mode 100644 index 00000000000..6d4dd4e8cb1 --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_machine_state.ts @@ -0,0 +1,93 @@ +import { Fr } from '@aztec/circuits.js'; + +import { TaggedMemory } from './avm_memory_types.js'; +import { AvmContractCallResults } from './avm_message_call_result.js'; + +/** + * A few fields of machine state are initialized from AVM session inputs or call instruction arguments + */ +export type InitialAvmMachineState = { + l1GasLeft: number; + l2GasLeft: number; + daGasLeft: number; +}; + +/** + * Avm state modified on an instruction-per-instruction basis. + */ +export class AvmMachineState { + public l1GasLeft: number; + /** gas remaining of the gas allocated for a contract call */ + public l2GasLeft: number; + public daGasLeft: number; + /** program counter */ + public pc: number = 0; + + /** + * On INTERNALCALL, internal call stack is pushed to with the current pc + 1 + * On INTERNALRETURN, value is popped from the internal call stack and assigned to the pc. + */ + public internalCallStack: number[] = []; + + /** Memory accessible to user code */ + public readonly memory: TaggedMemory = new TaggedMemory(); + + /** + * Signals that execution should end. + * AvmContext execution continues executing instructions until the machine state signals "halted" + * */ + public halted: boolean = false; + /** Signals that execution has reverted normally (this does not cover exceptional halts) */ + private reverted: boolean = false; + /** Output data must NOT be modified once it is set */ + private output: Fr[] = []; + + constructor(l1GasLeft: number, l2GasLeft: number, daGasLeft: number) { + this.l1GasLeft = l1GasLeft; + this.l2GasLeft = l2GasLeft; + this.daGasLeft = daGasLeft; + } + + public static fromState(state: InitialAvmMachineState): AvmMachineState { + return new AvmMachineState(state.l1GasLeft, state.l2GasLeft, state.daGasLeft); + } + + /** + * Most instructions just increment PC before they complete + */ + public incrementPc() { + this.pc++; + } + + /** + * Halt as successful + * Output data must NOT be modified once it is set + * @param output + */ + public return(output: Fr[]) { + this.halted = true; + this.output = output; + } + + /** + * Halt as reverted + * Output data must NOT be modified once it is set + * @param output + */ + public revert(output: Fr[]) { + this.halted = true; + this.reverted = true; + this.output = output; + } + + /** + * Get a summary of execution results for a halted machine state + * @returns summary of execution results + */ + public getResults(): AvmContractCallResults { + if (!this.halted) { + throw new Error('Execution results are not ready! Execution is ongoing.'); + } + return new AvmContractCallResults(this.reverted, this.output); + } +} diff --git a/yarn-project/simulator/src/avm/avm_memory_types.test.ts b/yarn-project/simulator/src/avm/avm_memory_types.test.ts new file mode 100644 index 00000000000..cdb581467de --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_memory_types.test.ts @@ -0,0 +1,182 @@ +import { Field, TaggedMemory, Uint8, Uint16, Uint32, Uint64, Uint128 } from './avm_memory_types.js'; + +describe('TaggedMemory', () => { + it('Elements should be undefined after construction', () => { + const mem = new TaggedMemory(); + expect(mem.get(10)).toBe(undefined); + }); + + it(`Should set and get integral types`, () => { + const mem = new TaggedMemory(); + mem.set(10, new Uint8(5)); + expect(mem.get(10)).toStrictEqual(new Uint8(5)); + }); + + it(`Should set and get field elements`, () => { + const mem = new TaggedMemory(); + mem.set(10, new Field(5)); + expect(mem.get(10)).toStrictEqual(new Field(5)); + }); + + it(`Should getSlice beyond current size`, () => { + const mem = new TaggedMemory(); + const val = [new Field(5), new Field(6)]; + + mem.setSlice(10, val); + + expect(mem.getSlice(10, /*size=*/ 4)).toEqual([...val, undefined, undefined]); + }); + + it(`Should set and get slices`, () => { + const mem = new TaggedMemory(); + const val = [new Field(5), new Field(6)]; + + mem.setSlice(10, val); + + expect(mem.getSlice(10, /*size=*/ 2)).toStrictEqual(val); + }); +}); + +type IntegralClass = typeof Uint8 | typeof Uint16 | typeof Uint32 | typeof Uint64 | typeof Uint128; +describe.each([Uint8, Uint16, Uint32, Uint64, Uint128])('Integral Types', (clsValue: IntegralClass) => { + it(`Should construct a new ${clsValue.name} from a number`, () => { + const x = new clsValue(5); + expect(x.toBigInt()).toStrictEqual(5n); + }); + + it(`Should construct a new ${clsValue.name} from a bigint`, () => { + const x = new clsValue(5n); + expect(x.toBigInt()).toStrictEqual(5n); + }); + + it(`Should build a new ${clsValue.name}`, () => { + const x = new clsValue(5); + const newX = x.build(10n); + expect(newX).toStrictEqual(new clsValue(10n)); + }); + + it(`Should add two ${clsValue.name} correctly`, () => { + const a = new clsValue(5); + const b = new clsValue(10); + const result = a.add(b); + expect(result).toStrictEqual(new clsValue(15n)); + }); + + it(`Should subtract two ${clsValue.name} correctly`, () => { + const a = new clsValue(10); + const b = new clsValue(5); + const result = a.sub(b); + expect(result).toStrictEqual(new clsValue(5n)); + }); + + it(`Should multiply two ${clsValue.name} correctly`, () => { + const a = new clsValue(5); + const b = new clsValue(10); + const result = a.mul(b); + expect(result).toStrictEqual(new clsValue(50n)); + }); + + it(`Should divide two ${clsValue.name} correctly`, () => { + const a = new clsValue(10); + const b = new clsValue(5); + const result = a.div(b); + expect(result).toStrictEqual(new clsValue(2n)); + }); + + it('Should shift right ${clsValue.name} correctly', () => { + const uintA = new clsValue(10); + const result = uintA.shr(new clsValue(1n)); + expect(result).toEqual(new clsValue(5n)); + }); + + it('Should shift left ${clsValue.name} correctly', () => { + const uintA = new clsValue(10); + const result = uintA.shl(new clsValue(1n)); + expect(result).toEqual(new clsValue(20n)); + }); + + it('Should and two ${clsValue.name} correctly', () => { + const uintA = new clsValue(10); + const uintB = new clsValue(5); + const result = uintA.and(uintB); + expect(result).toEqual(new clsValue(0n)); + }); + + it('Should or two ${clsValue.name} correctly', () => { + const uintA = new clsValue(10); + const uintB = new clsValue(5); + const result = uintA.or(uintB); + expect(result).toEqual(new clsValue(15n)); + }); + + it('Should xor two ${clsValue.name} correctly', () => { + const uintA = new clsValue(10); + const uintB = new clsValue(5); + const result = uintA.xor(uintB); + expect(result).toEqual(new clsValue(15n)); + }); + + it(`Should check equality of two ${clsValue.name} correctly`, () => { + const a = new clsValue(5); + const b = new clsValue(5); + const c = new clsValue(10); + expect(a.equals(b)).toBe(true); + expect(a.equals(c)).toBe(false); + }); + + it(`Should check if one ${clsValue.name} is less than another correctly`, () => { + const a = new clsValue(5); + const b = new clsValue(10); + expect(a.lt(b)).toBe(true); + expect(b.lt(a)).toBe(false); + }); +}); + +describe('Field', () => { + it(`Should build a new Field`, () => { + const field = new Field(5); + const newField = field.build(10n); + expect(newField.toBigInt()).toStrictEqual(10n); + }); + + it(`Should add two Fields correctly`, () => { + const field1 = new Field(5); + const field2 = new Field(10); + const result = field1.add(field2); + expect(result).toStrictEqual(new Field(15n)); + }); + + it(`Should subtract two Fields correctly`, () => { + const field1 = new Field(10); + const field2 = new Field(5); + const result = field1.sub(field2); + expect(result).toStrictEqual(new Field(5n)); + }); + + it(`Should multiply two Fields correctly`, () => { + const field1 = new Field(5); + const field2 = new Field(10); + const result = field1.mul(field2); + expect(result).toStrictEqual(new Field(50n)); + }); + + it(`Should divide two Fields correctly`, () => { + const field1 = new Field(10); + const field2 = new Field(5); + const result = field1.div(field2); + expect(result).toStrictEqual(new Field(2n)); + }); + + it(`Should check equality of two Fields correctly`, () => { + const field1 = new Field(5); + const field2 = new Field(5); + const field3 = new Field(10); + expect(field1.equals(field2)).toBe(true); + expect(field1.equals(field3)).toBe(false); + }); + + it(`Should convert Field to BigInt correctly`, () => { + const field = new Field(5); + expect(field.toBigInt()).toStrictEqual(5n); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts similarity index 81% rename from yarn-project/acir-simulator/src/avm/avm_memory_types.ts rename to yarn-project/simulator/src/avm/avm_memory_types.ts index 40c02b65463..f4fb0b80e9c 100644 --- a/yarn-project/acir-simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -2,6 +2,8 @@ import { Fr } from '@aztec/foundation/fields'; import { strict as assert } from 'assert'; +import { TagCheckError } from './errors.js'; + export abstract class MemoryValue { public abstract add(rhs: MemoryValue): MemoryValue; public abstract sub(rhs: MemoryValue): MemoryValue; @@ -9,7 +11,6 @@ export abstract class MemoryValue { public abstract div(rhs: MemoryValue): MemoryValue; public abstract equals(rhs: MemoryValue): boolean; - public abstract lt(rhs: MemoryValue): boolean; // We need this to be able to build an instance of the subclasses. public abstract build(n: bigint): MemoryValue; @@ -30,6 +31,8 @@ export abstract class IntegralValue extends MemoryValue { public abstract or(rhs: IntegralValue): IntegralValue; public abstract xor(rhs: IntegralValue): IntegralValue; public abstract not(): IntegralValue; + + public abstract lt(rhs: MemoryValue): boolean; } // TODO: Optimize calculation of mod, etc. Can only do once per class? @@ -198,10 +201,6 @@ export class Field extends MemoryValue { return this.rep.equals(rhs.rep); } - public lt(rhs: Field): boolean { - return this.rep.lt(rhs.rep); - } - public toBigInt(): bigint { return this.rep.toBigInt(); } @@ -221,15 +220,16 @@ export enum TypeTag { // TODO: Consider automatic conversion when getting undefined values. export class TaggedMemory { // FIXME: memory should be 2^32, but TS doesn't allow for arrays that big. - static readonly MAX_MEMORY_SIZE = Number(1n << 31n); // 1n << 32n + static readonly MAX_MEMORY_SIZE = Number((1n << 32n) - 2n); private _mem: MemoryValue[]; constructor() { - // Initialize memory size, but leave all entries undefined. - this._mem = new Array(TaggedMemory.MAX_MEMORY_SIZE); + // We do not initialize memory size here because otherwise tests blow up when diffing. + this._mem = []; } public get(offset: number): MemoryValue { + assert(offset < TaggedMemory.MAX_MEMORY_SIZE); return this.getAs(offset); } @@ -241,16 +241,19 @@ export class TaggedMemory { public getSlice(offset: number, size: number): MemoryValue[] { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); + assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE); return this._mem.slice(offset, offset + size); } public getSliceAs(offset: number, size: number): T[] { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); + assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE); return this._mem.slice(offset, offset + size) as T[]; } public getSliceTags(offset: number, size: number): TypeTag[] { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); + assert(offset + size < TaggedMemory.MAX_MEMORY_SIZE); return this._mem.slice(offset, offset + size).map(TaggedMemory.getTag); } @@ -261,6 +264,11 @@ export class TaggedMemory { public setSlice(offset: number, vs: MemoryValue[]) { assert(offset < TaggedMemory.MAX_MEMORY_SIZE); + assert(offset + vs.length < TaggedMemory.MAX_MEMORY_SIZE); + // We may need to extend the memory size, otherwise splice doesn't insert. + if (offset + vs.length > this._mem.length) { + this._mem.length = offset + vs.length; + } this._mem.splice(offset, vs.length, ...vs); } @@ -268,6 +276,39 @@ export class TaggedMemory { return TaggedMemory.getTag(this._mem[offset]); } + /** + * Check that the memory at the given offset matches the specified tag. + */ + public checkTag(tag: TypeTag, offset: number) { + if (this.getTag(offset) !== tag) { + throw TagCheckError.forOffset(offset, TypeTag[this.getTag(offset)], TypeTag[tag]); + } + } + + public static checkIsIntegralTag(tag: TypeTag) { + if (![TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128].includes(tag)) { + throw TagCheckError.forTag(TypeTag[tag], 'integral'); + } + } + + /** + * Check tags for memory at all of the specified offsets. + */ + public checkTags(tag: TypeTag, ...offsets: number[]) { + for (const offset of offsets) { + this.checkTag(tag, offset); + } + } + + /** + * Check tags for all memory in the specified range. + */ + public checkTagsRange(tag: TypeTag, startOffset: number, size: number) { + for (let offset = startOffset; offset < startOffset + size; offset++) { + this.checkTag(tag, offset); + } + } + // TODO: this might be slow, but I don't want to have the types know of their tags. // It might be possible to have a map. public static getTag(v: MemoryValue | undefined): TypeTag { @@ -293,8 +334,8 @@ export class TaggedMemory { } // Truncates the value to fit the type. - public static integralFromTag(v: bigint, tag: TypeTag): IntegralValue { - v = BigInt(v); // FIXME: not sure why this cast is needed, but this errors otherwise + public static integralFromTag(v: bigint | number, tag: TypeTag): IntegralValue { + v = v as bigint; switch (tag) { case TypeTag.UINT8: return new Uint8(v & ((1n << 8n) - 1n)); diff --git a/yarn-project/simulator/src/avm/avm_message_call_result.ts b/yarn-project/simulator/src/avm/avm_message_call_result.ts new file mode 100644 index 00000000000..3b7b4e87a0f --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_message_call_result.ts @@ -0,0 +1,29 @@ +import { Fr } from '@aztec/foundation/fields'; + +/** + * Results of an contract call's execution in the AVM. + */ +export class AvmContractCallResults { + public readonly reverted: boolean; + public readonly output: Fr[]; + + /** For exceptional halts */ + public readonly revertReason: Error | undefined; + + constructor(reverted: boolean, output: Fr[], revertReason?: Error) { + this.reverted = reverted; + this.output = output; + this.revertReason = revertReason; + } + + /** + * Generate a string representation of call results. + */ + toString(): string { + let resultsStr = `reverted: ${this.reverted}, output: ${this.output}`; + if (this.revertReason) { + resultsStr += `, revertReason: ${this.revertReason}`; + } + return resultsStr; + } +} diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts new file mode 100644 index 00000000000..e2231ede872 --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -0,0 +1,151 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; +import { AvmTestContractArtifact } from '@aztec/noir-contracts'; + +import { jest } from '@jest/globals'; + +import { TypeTag } from './avm_memory_types.js'; +import { AvmSimulator } from './avm_simulator.js'; +import { initContext, initExecutionEnvironment, initGlobalVariables } from './fixtures/index.js'; +import { Add, CalldataCopy, Return } from './opcodes/index.js'; +import { encodeToBytecode } from './serialization/bytecode_serialization.js'; + +describe('avm', () => { + it('Should execute bytecode that performs basic addition', async () => { + const calldata: Fr[] = [new Fr(1), new Fr(2)]; + + // Construct bytecode + const bytecode = encodeToBytecode([ + new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 2, /*dstOffset=*/ 0), + new Add(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), + new Return(/*indirect=*/ 0, /*returnOffset=*/ 2, /*copySize=*/ 1), + ]); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest.spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode').mockReturnValue(Promise.resolve(bytecode)); + + const results = await new AvmSimulator(context).execute(); + + expect(results.reverted).toBe(false); + + const returnData = results.output; + expect(returnData.length).toBe(1); + expect(returnData).toEqual([new Fr(3)]); + }); + + describe('testing transpiled Noir contracts', () => { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/4361): sync wire format w/transpiler. + it('Should execute contract function that performs addition', async () => { + const calldata: Fr[] = [new Fr(1), new Fr(2)]; + + // Get contract function artifact + const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_addArgsReturn')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(addArtifact.bytecode, 'base64'); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest.spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode').mockReturnValue(Promise.resolve(bytecode)); + + const results = await new AvmSimulator(context).execute(); + + expect(results.reverted).toBe(false); + + const returnData = results.output; + expect(returnData.length).toBe(1); + expect(returnData).toEqual([new Fr(3)]); + }); + + describe('Test env getters from noir contract', () => { + const testEnvGetter = async (valueName: string, value: any, functionName: string, globalVar: boolean = false) => { + const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; + + // Execute + let overrides = {}; + if (globalVar === true) { + const globals = initGlobalVariables({ [valueName]: value }); + overrides = { globals }; + } else { + overrides = { [valueName]: value }; + } + const context = initContext({ env: initExecutionEnvironment(overrides) }); + + // Decode bytecode into instructions + const bytecode = Buffer.from(getterArtifact.bytecode, 'base64'); + jest + .spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + // Execute + + const results = await new AvmSimulator(context).execute(); + + expect(results.reverted).toBe(false); + + const returnData = results.output; + expect(returnData.length).toBe(1); + expect(returnData).toEqual([value.toField()]); + }; + + it('address', async () => { + const address = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('address', address, 'avm_getAddress'); + }); + + it('storageAddress', async () => { + const storageAddress = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('storageAddress', storageAddress, 'avm_getStorageAddress'); + }); + + it('sender', async () => { + const sender = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('sender', sender, 'avm_getSender'); + }); + + it('origin', async () => { + const origin = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('origin', origin, 'avm_getOrigin'); + }); + + it('portal', async () => { + const portal = EthAddress.fromField(new Fr(1)); + await testEnvGetter('portal', portal, 'avm_getPortal'); + }); + + it('getFeePerL1Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL1Gas', fee, 'avm_getFeePerL1Gas'); + }); + + it('getFeePerL2Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL2Gas', fee, 'avm_getFeePerL2Gas'); + }); + + it('getFeePerDaGas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); + }); + + it('chainId', async () => { + const chainId = new Fr(1); + await testEnvGetter('chainId', chainId, 'avm_getChainId', /*globalVar=*/ true); + }); + + it('version', async () => { + const version = new Fr(1); + await testEnvGetter('version', version, 'avm_getVersion', /*globalVar=*/ true); + }); + + it('blockNumber', async () => { + const blockNumber = new Fr(1); + await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber', /*globalVar=*/ true); + }); + + it('timestamp', async () => { + const timestamp = new Fr(1); + await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp', /*globalVar=*/ true); + }); + }); + }); +}); diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts new file mode 100644 index 00000000000..a3c35012d00 --- /dev/null +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -0,0 +1,89 @@ +import { FunctionSelector } from '@aztec/circuits.js'; +import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; + +import { strict as assert } from 'assert'; + +import type { AvmContext } from './avm_context.js'; +import { AvmContractCallResults } from './avm_message_call_result.js'; +import { AvmExecutionError, InvalidProgramCounterError, NoBytecodeForContractError } from './errors.js'; +import type { Instruction } from './opcodes/index.js'; +import { decodeFromBytecode } from './serialization/bytecode_serialization.js'; + +export class AvmSimulator { + private log: DebugLogger = createDebugLogger('aztec:avm_simulator'); + + constructor(private context: AvmContext) {} + + /** + * Fetch the bytecode and execute it in the current context. + */ + public async execute(): Promise { + const instructions = await this.fetchAndDecodeBytecode(); + return this.executeInstructions(instructions); + } + + /** + * Executes the provided instructions in the current context. + * This method is useful for testing and debugging. + */ + public async executeInstructions(instructions: Instruction[]): Promise { + assert(instructions.length > 0); + + try { + // Execute instruction pointed to by the current program counter + // continuing until the machine state signifies a halt + while (!this.context.machineState.halted) { + const instruction = instructions[this.context.machineState.pc]; + assert(!!instruction); // This should never happen + + this.log(`Executing PC=${this.context.machineState.pc}: ${instruction.toString()}`); + // Execute the instruction. + // Normal returns and reverts will return normally here. + // "Exceptional halts" will throw. + await instruction.execute(this.context); + + if (this.context.machineState.pc >= instructions.length) { + this.log('Passed end of program!'); + throw new InvalidProgramCounterError(this.context.machineState.pc, /*max=*/ instructions.length); + } + } + + // Return results for processing by calling context + const results = this.context.machineState.getResults(); + this.log(`Context execution results: ${results.toString()}`); + return results; + } catch (e) { + this.log('Exceptional halt'); + if (!(e instanceof AvmExecutionError)) { + this.log(`Unknown error thrown by avm: ${e}`); + throw e; + } + + // Return results for processing by calling context + // Note: "exceptional halts" cannot return data + const results = new AvmContractCallResults(/*reverted=*/ true, /*output=*/ [], /*revertReason=*/ e); + this.log(`Context execution results: ${results.toString()}`); + return results; + } + } + + /** + * Fetch contract bytecode from world state and decode into executable instructions. + */ + private async fetchAndDecodeBytecode(): Promise { + // NOTE: the following is mocked as getPublicBytecode does not exist yet + const selector = new FunctionSelector(0); + const bytecode = await this.context.worldState.hostStorage.contractsDb.getBytecode( + this.context.environment.address, + selector, + ); + + // This assumes that we will not be able to send messages to accounts without code + // Pending classes and instances impl details + if (!bytecode) { + throw new NoBytecodeForContractError(this.context.environment.address); + } + + return decodeFromBytecode(bytecode); + } +} diff --git a/yarn-project/simulator/src/avm/errors.ts b/yarn-project/simulator/src/avm/errors.ts new file mode 100644 index 00000000000..24d52eea026 --- /dev/null +++ b/yarn-project/simulator/src/avm/errors.ts @@ -0,0 +1,57 @@ +import { AztecAddress } from '@aztec/circuits.js'; + +/** + * Avm-specific errors should derive from this + */ +export abstract class AvmExecutionError extends Error { + constructor(message: string, ...rest: any[]) { + super(message, ...rest); + this.name = 'AvmInterpreterError'; + } +} + +export class NoBytecodeForContractError extends AvmExecutionError { + constructor(contractAddress: AztecAddress) { + super(`No bytecode found at: ${contractAddress}`); + this.name = 'NoBytecodeFoundInterpreterError'; + } +} + +/** + * Error is thrown when the program counter goes to an invalid location. + * There is no instruction at the provided pc + */ +export class InvalidProgramCounterError extends AvmExecutionError { + constructor(pc: number, max: number) { + super(`Invalid program counter ${pc}, max is ${max}`); + this.name = 'InvalidProgramCounterError'; + } +} + +/** + * Error thrown during an instruction's execution (during its execute()). + */ +export class InstructionExecutionError extends AvmExecutionError { + constructor(message: string) { + super(message); + this.name = 'InstructionExecutionError'; + } +} + +/** + * Error thrown on failed AVM memory tag check. + */ +export class TagCheckError extends AvmExecutionError { + public static forOffset(offset: number, gotTag: string, expectedTag: string): TagCheckError { + return new TagCheckError(`Tag mismatch at offset ${offset}, got ${gotTag}, expected ${expectedTag}`); + } + + public static forTag(gotTag: string, expectedTag: string): TagCheckError { + return new TagCheckError(`Tag mismatch, got ${gotTag}, expected ${expectedTag}`); + } + + constructor(message: string) { + super(message); + this.name = 'TagCheckError'; + } +} diff --git a/yarn-project/simulator/src/avm/fixtures/index.ts b/yarn-project/simulator/src/avm/fixtures/index.ts new file mode 100644 index 00000000000..bcaf1ff779f --- /dev/null +++ b/yarn-project/simulator/src/avm/fixtures/index.ts @@ -0,0 +1,88 @@ +import { GlobalVariables } from '@aztec/circuits.js'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { mock } from 'jest-mock-extended'; +import merge from 'lodash.merge'; + +import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; +import { AvmContext } from '../avm_context.js'; +import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; +import { AvmMachineState } from '../avm_machine_state.js'; +import { HostStorage } from '../journal/host_storage.js'; +import { AvmWorldStateJournal } from '../journal/journal.js'; + +/** + * Create a new AVM context with default values. + */ +export function initContext(overrides?: { + worldState?: AvmWorldStateJournal; + env?: AvmExecutionEnvironment; + machineState?: AvmMachineState; +}): AvmContext { + return new AvmContext( + overrides?.worldState || initMockWorldStateJournal(), + overrides?.env || initExecutionEnvironment(), + overrides?.machineState || initMachineState(), + ); +} + +/** Creates an empty world state with mocked storage. */ +export function initMockWorldStateJournal(): AvmWorldStateJournal { + const hostStorage = new HostStorage(mock(), mock(), mock()); + return new AvmWorldStateJournal(hostStorage); +} + +/** + * Create an empty instance of the Execution Environment where all values are zero, unless overridden in the overrides object + */ +export function initExecutionEnvironment(overrides?: Partial): AvmExecutionEnvironment { + return new AvmExecutionEnvironment( + overrides?.address ?? AztecAddress.zero(), + overrides?.storageAddress ?? AztecAddress.zero(), + overrides?.origin ?? AztecAddress.zero(), + overrides?.sender ?? AztecAddress.zero(), + overrides?.portal ?? EthAddress.ZERO, + overrides?.feePerL1Gas ?? Fr.zero(), + overrides?.feePerL2Gas ?? Fr.zero(), + overrides?.feePerDaGas ?? Fr.zero(), + overrides?.contractCallDepth ?? Fr.zero(), + overrides?.globals ?? GlobalVariables.empty(), + overrides?.isStaticCall ?? false, + overrides?.isDelegateCall ?? false, + overrides?.calldata ?? [], + ); +} + +/** + * Create an empty instance of the Execution Environment where all values are zero, unless overridden in the overrides object + */ +export function initGlobalVariables(overrides?: Partial): GlobalVariables { + return new GlobalVariables( + overrides?.chainId ?? Fr.zero(), + overrides?.version ?? Fr.zero(), + overrides?.blockNumber ?? Fr.zero(), + overrides?.timestamp ?? Fr.zero(), + overrides?.coinbase ?? EthAddress.ZERO, + overrides?.feeRecipient ?? AztecAddress.zero(), + ); +} + +/** + * Create an empty instance of the Machine State where all values are zero, unless overridden in the overrides object + */ +export function initMachineState(overrides?: Partial): AvmMachineState { + return AvmMachineState.fromState({ + l1GasLeft: overrides?.l1GasLeft ?? 0, + l2GasLeft: overrides?.l2GasLeft ?? 0, + daGasLeft: overrides?.daGasLeft ?? 0, + }); +} + +/** + * Create a new object with all the same properties as the original, except for the ones in the overrides object. + */ +export function allSameExcept(original: any, overrides: any): any { + return merge({}, original, overrides); +} diff --git a/yarn-project/acir-simulator/src/avm/journal/host_storage.ts b/yarn-project/simulator/src/avm/journal/host_storage.ts similarity index 100% rename from yarn-project/acir-simulator/src/avm/journal/host_storage.ts rename to yarn-project/simulator/src/avm/journal/host_storage.ts diff --git a/yarn-project/acir-simulator/src/avm/journal/index.ts b/yarn-project/simulator/src/avm/journal/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/avm/journal/index.ts rename to yarn-project/simulator/src/avm/journal/index.ts diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts b/yarn-project/simulator/src/avm/journal/journal.test.ts similarity index 84% rename from yarn-project/acir-simulator/src/avm/journal/journal.test.ts rename to yarn-project/simulator/src/avm/journal/journal.test.ts index 2a3aafd6da6..0a2b8c4b1b3 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/simulator/src/avm/journal/journal.test.ts @@ -3,13 +3,12 @@ import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; -import { RootJournalCannotBeMerged } from './errors.js'; import { HostStorage } from './host_storage.js'; -import { AvmJournal, JournalData } from './journal.js'; +import { AvmWorldStateJournal, JournalData } from './journal.js'; describe('journal', () => { let publicDb: MockProxy; - let journal: AvmJournal; + let journal: AvmWorldStateJournal; beforeEach(() => { publicDb = mock(); @@ -17,7 +16,7 @@ describe('journal', () => { const contractsDb = mock(); const hostStorage = new HostStorage(publicDb, contractsDb, commitmentsDb); - journal = new AvmJournal(hostStorage); + journal = new AvmWorldStateJournal(hostStorage); }); describe('Public Storage', () => { @@ -43,7 +42,7 @@ describe('journal', () => { publicDb.storageRead.mockResolvedValue(Promise.resolve(storedValue)); - const childJournal = new AvmJournal(journal.hostStorage, journal); + const childJournal = new AvmWorldStateJournal(journal.hostStorage, journal); // Get the cache miss const cacheMissResult = await childJournal.readStorage(contractAddress, key); @@ -144,15 +143,15 @@ describe('journal', () => { journal.writeL1Message(logs); journal.writeNullifier(commitment); - const journal1 = new AvmJournal(journal.hostStorage, journal); - journal1.writeStorage(contractAddress, key, valueT1); - await journal1.readStorage(contractAddress, key); - journal1.writeNoteHash(commitmentT1); - journal1.writeLog(logsT1); - journal1.writeL1Message(logsT1); - journal1.writeNullifier(commitmentT1); + const childJournal = new AvmWorldStateJournal(journal.hostStorage, journal); + childJournal.writeStorage(contractAddress, key, valueT1); + await childJournal.readStorage(contractAddress, key); + childJournal.writeNoteHash(commitmentT1); + childJournal.writeLog(logsT1); + childJournal.writeL1Message(logsT1); + childJournal.writeNullifier(commitmentT1); - journal1.mergeSuccessWithParent(); + journal.acceptNestedWorldState(childJournal); const result = await journal.readStorage(contractAddress, key); expect(result).toEqual(valueT1); @@ -204,15 +203,15 @@ describe('journal', () => { journal.writeL1Message(logs); journal.writeNullifier(commitment); - const journal1 = new AvmJournal(journal.hostStorage, journal); - journal1.writeStorage(contractAddress, key, valueT1); - await journal1.readStorage(contractAddress, key); - journal1.writeNoteHash(commitmentT1); - journal1.writeLog(logsT1); - journal1.writeL1Message(logsT1); - journal1.writeNullifier(commitmentT1); + const childJournal = new AvmWorldStateJournal(journal.hostStorage, journal); + childJournal.writeStorage(contractAddress, key, valueT1); + await childJournal.readStorage(contractAddress, key); + childJournal.writeNoteHash(commitmentT1); + childJournal.writeLog(logsT1); + childJournal.writeL1Message(logsT1); + childJournal.writeNullifier(commitmentT1); - journal1.mergeFailureWithParent(); + journal.rejectNestedWorldState(childJournal); // Check that the storage is reverted by reading from the journal const result = await journal.readStorage(contractAddress, key); @@ -239,14 +238,11 @@ describe('journal', () => { expect(journalUpdates.newNullifiers).toEqual([commitment]); }); - it('Cannot merge a root journal, but can merge a child journal', () => { - const rootJournal = AvmJournal.rootJournal(journal.hostStorage); - const childJournal = AvmJournal.branchParent(rootJournal); + it('Can fork and merge journals', () => { + const rootJournal = new AvmWorldStateJournal(journal.hostStorage); + const childJournal = rootJournal.fork(); - expect(() => rootJournal.mergeSuccessWithParent()).toThrow(RootJournalCannotBeMerged); - expect(() => rootJournal.mergeFailureWithParent()).toThrow(RootJournalCannotBeMerged); - - expect(() => childJournal.mergeSuccessWithParent()); - expect(() => childJournal.mergeFailureWithParent()); + expect(() => rootJournal.acceptNestedWorldState(childJournal)); + expect(() => rootJournal.rejectNestedWorldState(childJournal)); }); }); diff --git a/yarn-project/acir-simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts similarity index 79% rename from yarn-project/acir-simulator/src/avm/journal/journal.ts rename to yarn-project/simulator/src/avm/journal/journal.ts index 3b2445e7dc6..cdeb4b4ff92 100644 --- a/yarn-project/acir-simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -1,6 +1,5 @@ import { Fr } from '@aztec/foundation/fields'; -import { RootJournalCannotBeMerged } from './errors.js'; import { HostStorage } from './host_storage.js'; /** @@ -25,11 +24,11 @@ export type JournalData = { * A cache of the current state of the AVM * The interpreter should make any state queries through this object * - * When a sub context's call succeeds, it's journal is merge into the parent - * When a a call fails, it's journal is discarded and the parent is used from this point forward + * When a nested context succeeds, it's journal is merge into the parent + * When a call fails, it's journal is discarded and the parent is used from this point forward * When a call succeeds's we can merge a child into its parent */ -export class AvmJournal { +export class AvmWorldStateJournal { /** Reference to node storage */ public readonly hostStorage: HostStorage; @@ -49,27 +48,18 @@ export class AvmJournal { // contract address -> key -> value private currentStorageValue: Map> = new Map(); - private parentJournal: AvmJournal | undefined; + private parentJournal: AvmWorldStateJournal | undefined; - constructor(hostStorage: HostStorage, parentJournal?: AvmJournal) { + constructor(hostStorage: HostStorage, parentJournal?: AvmWorldStateJournal) { this.hostStorage = hostStorage; this.parentJournal = parentJournal; } /** - * Create a new root journal, without a parent - * @param hostStorage - + * Create a new world state journal forked from this one */ - public static rootJournal(hostStorage: HostStorage) { - return new AvmJournal(hostStorage); - } - - /** - * Create a new journal from a parent - * @param parentJournal - - */ - public static branchParent(parentJournal: AvmJournal) { - return new AvmJournal(parentJournal.hostStorage, parentJournal); + public fork() { + return new AvmWorldStateJournal(this.hostStorage, this); } /** @@ -162,44 +152,36 @@ export class AvmJournal { } /** - * Merge Journal from successful call into parent + * Accept nested world state, merging in its journal, and accepting its state modifications * - Utxo objects are concatenated * - Public state changes are merged, with the value in the incoming journal taking precedent * - Public state journals (r/w logs), with the accessing being appended in chronological order */ - public mergeSuccessWithParent() { - if (!this.parentJournal) { - throw new RootJournalCannotBeMerged(); - } - + public acceptNestedWorldState(nestedJournal: AvmWorldStateJournal) { // Merge UTXOs - this.parentJournal.newNoteHashes = this.parentJournal.newNoteHashes.concat(this.newNoteHashes); - this.parentJournal.newL1Messages = this.parentJournal.newL1Messages.concat(this.newL1Messages); - this.parentJournal.newNullifiers = this.parentJournal.newNullifiers.concat(this.newNullifiers); - this.parentJournal.newLogs = this.parentJournal.newLogs.concat(this.newLogs); + this.newNoteHashes = this.newNoteHashes.concat(nestedJournal.newNoteHashes); + this.newL1Messages = this.newL1Messages.concat(nestedJournal.newL1Messages); + this.newNullifiers = this.newNullifiers.concat(nestedJournal.newNullifiers); + this.newLogs = this.newLogs.concat(nestedJournal.newLogs); // Merge Public State - mergeCurrentValueMaps(this.parentJournal.currentStorageValue, this.currentStorageValue); + mergeCurrentValueMaps(this.currentStorageValue, nestedJournal.currentStorageValue); // Merge storage read and write journals - mergeContractJournalMaps(this.parentJournal.storageReads, this.storageReads); - mergeContractJournalMaps(this.parentJournal.storageWrites, this.storageWrites); + mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads); + mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites); } /** - * Merge Journal for failed call into parent + * Reject nested world state, merging in its journal, but not accepting its state modifications * - Utxo objects are concatenated * - Public state changes are dropped * - Public state journals (r/w logs) are maintained, with the accessing being appended in chronological order */ - public mergeFailureWithParent() { - if (!this.parentJournal) { - throw new RootJournalCannotBeMerged(); - } - + public rejectNestedWorldState(nestedJournal: AvmWorldStateJournal) { // Merge storage read and write journals - mergeContractJournalMaps(this.parentJournal.storageReads, this.storageReads); - mergeContractJournalMaps(this.parentJournal.storageWrites, this.storageWrites); + mergeContractJournalMaps(this.storageReads, nestedJournal.storageReads); + mergeContractJournalMaps(this.storageWrites, nestedJournal.storageWrites); } /** diff --git a/yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs b/yarn-project/simulator/src/avm/opcodes/.eslintrc.cjs similarity index 100% rename from yarn-project/acir-simulator/src/avm/opcodes/.eslintrc.cjs rename to yarn-project/simulator/src/avm/opcodes/.eslintrc.cjs diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts similarity index 76% rename from yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts rename to yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 0163b8bea21..83996e1e3b7 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -1,21 +1,14 @@ -import { mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { HostStorage } from '../journal/host_storage.js'; -import { AvmJournal } from '../journal/journal.js'; +import { initContext, initExecutionEnvironment } from '../fixtures/index.js'; import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, SendL2ToL1Message } from './accrued_substate.js'; import { StaticCallStorageAlterError } from './storage.js'; describe('Accrued Substate', () => { - let journal: AvmJournal; - let machineState: AvmMachineState; + let context: AvmContext; beforeEach(() => { - const hostStorage = mock(); - journal = new AvmJournal(hostStorage); - machineState = new AvmMachineState(initExecutionEnvironment()); + context = initContext(); }); describe('EmitNoteHash', () => { @@ -33,11 +26,11 @@ describe('Accrued Substate', () => { it('Should append a new note hash correctly', async () => { const value = new Field(69n); - machineState.memory.set(0, value); + context.machineState.memory.set(0, value); - await new EmitNoteHash(/*indirect=*/ 0, /*offset=*/ 0).execute(machineState, journal); + await new EmitNoteHash(/*indirect=*/ 0, /*offset=*/ 0).execute(context); - const journalState = journal.flush(); + const journalState = context.worldState.flush(); const expected = [value.toFr()]; expect(journalState.newNoteHashes).toEqual(expected); }); @@ -58,11 +51,11 @@ describe('Accrued Substate', () => { it('Should append a new nullifier correctly', async () => { const value = new Field(69n); - machineState.memory.set(0, value); + context.machineState.memory.set(0, value); - await new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(machineState, journal); + await new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context); - const journalState = journal.flush(); + const journalState = context.worldState.flush(); const expected = [value.toFr()]; expect(journalState.newNullifiers).toEqual(expected); }); @@ -86,13 +79,13 @@ describe('Accrued Substate', () => { const startOffset = 0; const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; - machineState.memory.setSlice(0, values); + context.machineState.memory.setSlice(0, values); const length = values.length; - await new EmitUnencryptedLog(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(machineState, journal); + await new EmitUnencryptedLog(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(context); - const journalState = journal.flush(); + const journalState = context.worldState.flush(); const expected = values.map(v => v.toFr()); expect(journalState.newLogs).toEqual([expected]); }); @@ -116,21 +109,20 @@ describe('Accrued Substate', () => { const startOffset = 0; const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; - machineState.memory.setSlice(0, values); + context.machineState.memory.setSlice(0, values); const length = values.length; - await new SendL2ToL1Message(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(machineState, journal); + await new SendL2ToL1Message(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(context); - const journalState = journal.flush(); + const journalState = context.worldState.flush(); const expected = values.map(v => v.toFr()); expect(journalState.newL1Messages).toEqual([expected]); }); }); it('All substate instructions should fail within a static call', async () => { - const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); - machineState = new AvmMachineState(executionEnvironment); + context = initContext({ env: initExecutionEnvironment({ isStaticCall: true }) }); const instructions = [ new EmitNoteHash(/*indirect=*/ 0, /*offset=*/ 0), @@ -140,7 +132,7 @@ describe('Accrued Substate', () => { ]; for (const instruction of instructions) { - await expect(instruction.execute(machineState, journal)).rejects.toThrow(StaticCallStorageAlterError); + await expect(instruction.execute(context)).rejects.toThrow(StaticCallStorageAlterError); } }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts similarity index 61% rename from yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts rename to yarn-project/simulator/src/avm/opcodes/accrued_substate.ts index 1e85dde5d20..a59da301337 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts @@ -1,5 +1,4 @@ -import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmJournal } from '../journal/journal.js'; +import type { AvmContext } from '../avm_context.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; @@ -14,15 +13,15 @@ export class EmitNoteHash extends Instruction { super(); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - if (machineState.executionEnvironment.isStaticCall) { + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { throw new StaticCallStorageAlterError(); } - const noteHash = machineState.memory.get(this.noteHashOffset).toFr(); - journal.writeNoteHash(noteHash); + const noteHash = context.machineState.memory.get(this.noteHashOffset).toFr(); + context.worldState.writeNoteHash(noteHash); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -36,15 +35,15 @@ export class EmitNullifier extends Instruction { super(); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - if (machineState.executionEnvironment.isStaticCall) { + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { throw new StaticCallStorageAlterError(); } - const nullifier = machineState.memory.get(this.nullifierOffset).toFr(); - journal.writeNullifier(nullifier); + const nullifier = context.machineState.memory.get(this.nullifierOffset).toFr(); + context.worldState.writeNullifier(nullifier); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -58,15 +57,15 @@ export class EmitUnencryptedLog extends Instruction { super(); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - if (machineState.executionEnvironment.isStaticCall) { + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { throw new StaticCallStorageAlterError(); } - const log = machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr()); - journal.writeLog(log); + const log = context.machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr()); + context.worldState.writeLog(log); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -80,14 +79,14 @@ export class SendL2ToL1Message extends Instruction { super(); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - if (machineState.executionEnvironment.isStaticCall) { + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { throw new StaticCallStorageAlterError(); } - const msg = machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr()); - journal.writeL1Message(msg); + const msg = context.machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr()); + context.worldState.writeL1Message(msg); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } diff --git a/yarn-project/simulator/src/avm/opcodes/addressing_mode.test.ts b/yarn-project/simulator/src/avm/opcodes/addressing_mode.test.ts new file mode 100644 index 00000000000..e80f687b672 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/addressing_mode.test.ts @@ -0,0 +1,49 @@ +import { TaggedMemory, Uint32 } from '../avm_memory_types.js'; +import { Addressing, AddressingMode } from './addressing_mode.js'; + +describe('Addressing', () => { + it('should reserialize correctly', () => { + const addressingMode = Addressing.fromWire(0b10101010); + const wireModes = addressingMode.toWire(); + expect(wireModes).toBe(0b10101010); + }); + + it('should convert to wire format correctly', () => { + const addressingMode = new Addressing([ + AddressingMode.INDIRECT, + AddressingMode.DIRECT, + AddressingMode.INDIRECT, + AddressingMode.DIRECT, + ]); + const wireModes = addressingMode.toWire(); + expect(wireModes).toBe(0b00000101); + }); + + it('should convert from wire format correctly', () => { + const addressingMode = Addressing.fromWire(0b00011001); + const expected = new Addressing([ + AddressingMode.INDIRECT, + AddressingMode.DIRECT, + AddressingMode.DIRECT, + AddressingMode.INDIRECT, + AddressingMode.INDIRECT, + AddressingMode.DIRECT, + AddressingMode.DIRECT, + AddressingMode.DIRECT, + ]); + + expect(addressingMode).toStrictEqual(expected); + }); + + it('should resolve offsets correctly', () => { + const addressingMode = Addressing.fromWire(0b00011001); + const offsets = [10, 20, 30]; + const mem = new TaggedMemory(); + mem.set(10, new Uint32(100)); + mem.set(20, new Uint32(200)); + mem.set(30, new Uint32(300)); + + const resolved = addressingMode.resolve(offsets, mem); + expect(resolved).toEqual([100, 20, 30]); + }); +}); diff --git a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts new file mode 100644 index 00000000000..1fb4137205a --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts @@ -0,0 +1,66 @@ +import { strict as assert } from 'assert'; + +import { TaggedMemory, TypeTag } from '../avm_memory_types.js'; + +export enum AddressingMode { + DIRECT, + INDIRECT, + INDIRECT_PLUS_CONSTANT, // Not implemented yet. +} + +/** A class to represent the addressing mode of an instruction. */ +export class Addressing { + public constructor( + /** The addressing mode for each operand. The length of this array is the number of operands of the instruction. */ + private readonly modePerOperand: AddressingMode[], + ) { + assert(modePerOperand.length <= 8, 'At most 8 operands are supported'); + } + + public static fromWire(wireModes: number): Addressing { + // The modes are stored in the wire format as a byte, with each bit representing the mode for an operand. + // The least significant bit represents the zeroth operand, and the most significant bit represents the last operand. + const modes = new Array(8); + for (let i = 0; i < 8; i++) { + modes[i] = (wireModes & (1 << i)) === 0 ? AddressingMode.DIRECT : AddressingMode.INDIRECT; + } + return new Addressing(modes); + } + + public toWire(): number { + // The modes are stored in the wire format as a byte, with each bit representing the mode for an operand. + // The least significant bit represents the zeroth operand, and the least significant bit represents the last operand. + let wire: number = 0; + for (let i = 0; i < 8; i++) { + if (this.modePerOperand[i] === AddressingMode.INDIRECT) { + wire |= 1 << i; + } + } + return wire; + } + + /** + * Resolves the offsets using the addressing mode. + * @param offsets The offsets to resolve. + * @param mem The memory to use for resolution. + * @returns The resolved offsets. The length of the returned array is the same as the length of the input array. + */ + public resolve(offsets: number[], mem: TaggedMemory): number[] { + assert(offsets.length <= this.modePerOperand.length); + const resolved = new Array(offsets.length); + for (const [i, offset] of offsets.entries()) { + switch (this.modePerOperand[i]) { + case AddressingMode.INDIRECT: + mem.checkTag(TypeTag.UINT32, offset); + resolved[i] = Number(mem.get(offset).toBigInt()); + break; + case AddressingMode.DIRECT: + resolved[i] = offset; + break; + default: + throw new Error(`Unimplemented addressing mode: ${AddressingMode[this.modePerOperand[i]]}`); + } + } + return resolved; + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts similarity index 76% rename from yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts rename to yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts index f54db2d82a7..e08fe4bcb8e 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts @@ -1,18 +1,13 @@ -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field, TypeTag } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; +import { initContext } from '../fixtures/index.js'; import { Add, Div, Mul, Sub } from './arithmetic.js'; describe('Arithmetic Instructions', () => { - let machineState: AvmMachineState; - let journal: MockProxy; + let context: AvmContext; - beforeEach(async () => { - machineState = new AvmMachineState(initExecutionEnvironment()); - journal = mock(); + beforeEach(() => { + context = initContext(); }); describe('Add', () => { @@ -41,8 +36,8 @@ describe('Arithmetic Instructions', () => { const a = new Field(1n); const b = new Field(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Add( /*indirect=*/ 0, @@ -50,10 +45,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Field(3n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -61,8 +56,8 @@ describe('Arithmetic Instructions', () => { const a = new Field(1n); const b = new Field(Field.MODULUS - 1n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Add( /*indirect=*/ 0, @@ -70,10 +65,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Field(0n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -104,8 +99,8 @@ describe('Arithmetic Instructions', () => { const a = new Field(1n); const b = new Field(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Sub( /*indirect=*/ 0, @@ -113,10 +108,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Field(Field.MODULUS - 1n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -147,8 +142,8 @@ describe('Arithmetic Instructions', () => { const a = new Field(2n); const b = new Field(3n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Mul( /*indirect=*/ 0, @@ -156,10 +151,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Field(6n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -167,8 +162,8 @@ describe('Arithmetic Instructions', () => { const a = new Field(2n); const b = new Field(Field.MODULUS / 2n - 1n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Mul( /*indirect=*/ 0, @@ -176,10 +171,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Field(Field.MODULUS - 3n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -207,11 +202,11 @@ describe('Arithmetic Instructions', () => { }); it('Should perform field division', async () => { - const a = new Field(2n); - const b = new Field(3n); + const a = new Field(10n); + const b = new Field(5n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Div( /*indirect=*/ 0, @@ -219,11 +214,10 @@ describe('Arithmetic Instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); - const actual = machineState.memory.get(2); - const recovered = actual.mul(b); - expect(recovered).toEqual(a); + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(new Field(2)); }); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts b/yarn-project/simulator/src/avm/opcodes/arithmetic.ts similarity index 54% rename from yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts rename to yarn-project/simulator/src/avm/opcodes/arithmetic.ts index 71a571b45dd..91c5a44a6dc 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/arithmetic.ts +++ b/yarn-project/simulator/src/avm/opcodes/arithmetic.ts @@ -1,5 +1,4 @@ -import { AvmMachineState } from '../avm_machine_state.js'; -import { AvmJournal } from '../journal/index.js'; +import type { AvmContext } from '../avm_context.js'; import { Opcode } from '../serialization/instruction_serialization.js'; import { ThreeOperandInstruction } from './instruction_impl.js'; @@ -11,14 +10,14 @@ export class Add extends ThreeOperandInstruction { super(indirect, inTag, aOffset, bOffset, dstOffset); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); const dest = a.add(b); - machineState.memory.set(this.dstOffset, dest); + context.machineState.memory.set(this.dstOffset, dest); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -30,14 +29,14 @@ export class Sub extends ThreeOperandInstruction { super(indirect, inTag, aOffset, bOffset, dstOffset); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); const dest = a.sub(b); - machineState.memory.set(this.dstOffset, dest); + context.machineState.memory.set(this.dstOffset, dest); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -49,14 +48,14 @@ export class Mul extends ThreeOperandInstruction { super(indirect, inTag, aOffset, bOffset, dstOffset); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); const dest = a.mul(b); - machineState.memory.set(this.dstOffset, dest); + context.machineState.memory.set(this.dstOffset, dest); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -68,13 +67,13 @@ export class Div extends ThreeOperandInstruction { super(indirect, inTag, aOffset, bOffset, dstOffset); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const a = machineState.memory.get(this.aOffset); - const b = machineState.memory.get(this.bOffset); + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); const dest = a.div(b); - machineState.memory.set(this.dstOffset, dest); + context.machineState.memory.set(this.dstOffset, dest); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts b/yarn-project/simulator/src/avm/opcodes/bitwise.test.ts similarity index 78% rename from yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts rename to yarn-project/simulator/src/avm/opcodes/bitwise.test.ts index d41c34611e0..8a16f215f03 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/bitwise.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/bitwise.test.ts @@ -1,18 +1,13 @@ -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { TypeTag, Uint16, Uint32 } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; +import { initContext } from '../fixtures/index.js'; import { And, Not, Or, Shl, Shr, Xor } from './bitwise.js'; describe('Bitwise instructions', () => { - let machineState: AvmMachineState; - let journal: MockProxy; + let context: AvmContext; - beforeEach(async () => { - machineState = new AvmMachineState(initExecutionEnvironment()); - journal = mock(); + beforeEach(() => { + context = initContext(); }); describe('AND', () => { @@ -38,8 +33,8 @@ describe('Bitwise instructions', () => { }); it('Should AND correctly over integral types', async () => { - machineState.memory.set(0, new Uint32(0b11111110010011100100n)); - machineState.memory.set(1, new Uint32(0b11100100111001001111n)); + context.machineState.memory.set(0, new Uint32(0b11111110010011100100n)); + context.machineState.memory.set(1, new Uint32(0b11100100111001001111n)); await new And( /*indirect=*/ 0, @@ -47,9 +42,9 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(new Uint32(0b11100100010001000100n)); }); }); @@ -80,8 +75,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Or( /*indirect=*/ 0, @@ -89,10 +84,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint32(0b11111110111011101111n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -123,8 +118,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0b11100100111001001111n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Xor( /*indirect=*/ 0, @@ -132,10 +127,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint32(0b00011010101010101011n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -166,8 +161,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shr( /*indirect=*/ 0, @@ -175,10 +170,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = a; - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -186,8 +181,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shr( /*indirect=*/ 0, @@ -195,10 +190,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint32(0b00111111100100111001n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -206,8 +201,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(19n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shr( /*indirect=*/ 0, @@ -215,10 +210,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint32(0b01n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -249,8 +244,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(0n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shl( /*indirect=*/ 0, @@ -258,10 +253,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = a; - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -269,8 +264,8 @@ describe('Bitwise instructions', () => { const a = new Uint32(0b11111110010011100100n); const b = new Uint32(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shl( /*indirect=*/ 0, @@ -278,10 +273,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint32(0b1111111001001110010000n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -289,8 +284,8 @@ describe('Bitwise instructions', () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(17n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shl( /*indirect=*/ 0, @@ -298,10 +293,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint16(0n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); @@ -309,8 +304,8 @@ describe('Bitwise instructions', () => { const a = new Uint16(0b1110010011100111n); const b = new Uint16(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); await new Shl( /*indirect=*/ 0, @@ -318,10 +313,10 @@ describe('Bitwise instructions', () => { /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2, - ).execute(machineState, journal); + ).execute(context); const expected = new Uint16(0b1001001110011100n); - const actual = machineState.memory.get(2); + const actual = context.machineState.memory.get(2); expect(actual).toEqual(expected); }); }); @@ -349,15 +344,12 @@ describe('Bitwise instructions', () => { it('Should NOT correctly over integral types', async () => { const a = new Uint16(0b0110010011100100n); - machineState.memory.set(0, a); + context.machineState.memory.set(0, a); - await new Not(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*aOffset=*/ 0, /*dstOffset=*/ 1).execute( - machineState, - journal, - ); + await new Not(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*aOffset=*/ 0, /*dstOffset=*/ 1).execute(context); const expected = new Uint16(0b1001101100011011n); // high bits! - const actual = machineState.memory.get(1); + const actual = context.machineState.memory.get(1); expect(actual).toEqual(expected); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/bitwise.ts b/yarn-project/simulator/src/avm/opcodes/bitwise.ts new file mode 100644 index 00000000000..9161c8bb22c --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/bitwise.ts @@ -0,0 +1,129 @@ +import type { AvmContext } from '../avm_context.js'; +import { IntegralValue } from '../avm_memory_types.js'; +import { Opcode } from '../serialization/instruction_serialization.js'; +import { ThreeOperandInstruction, TwoOperandInstruction } from './instruction_impl.js'; + +export class And extends ThreeOperandInstruction { + static readonly type: string = 'AND'; + static readonly opcode = Opcode.AND; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + const res = a.and(b); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class Or extends ThreeOperandInstruction { + static readonly type: string = 'OR'; + static readonly opcode = Opcode.OR; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + const res = a.or(b); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class Xor extends ThreeOperandInstruction { + static readonly type: string = 'XOR'; + static readonly opcode = Opcode.XOR; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + const res = a.xor(b); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class Not extends TwoOperandInstruction { + static readonly type: string = 'NOT'; + static readonly opcode = Opcode.NOT; + + constructor(indirect: number, inTag: number, aOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + + const res = a.not(); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class Shl extends ThreeOperandInstruction { + static readonly type: string = 'SHL'; + static readonly opcode = Opcode.SHL; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + const res = a.shl(b); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class Shr extends ThreeOperandInstruction { + static readonly type: string = 'SHR'; + static readonly opcode = Opcode.SHR; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + const res = a.shr(b); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts similarity index 64% rename from yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts rename to yarn-project/simulator/src/avm/opcodes/comparators.test.ts index b707b138aa7..591c657239e 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/comparators.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts @@ -1,19 +1,14 @@ -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field, TypeTag, Uint16, Uint32 } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; +import { TagCheckError } from '../errors.js'; +import { initContext } from '../fixtures/index.js'; import { Eq, Lt, Lte } from './comparators.js'; -import { InstructionExecutionError } from './instruction.js'; describe('Comparators', () => { - let machineState: AvmMachineState; - let journal: MockProxy; + let context: AvmContext; - beforeEach(async () => { - machineState = new AvmMachineState(initExecutionEnvironment()); - journal = mock(); + beforeEach(() => { + context = initContext(); }); describe('Eq', () => { @@ -39,33 +34,33 @@ describe('Comparators', () => { }); it('Works on integral types', async () => { - machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(3), new Uint32(1)]); + context.machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(3), new Uint32(1)]); [ new Eq(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), new Eq(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 11), new Eq(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); expect(actual).toEqual([new Uint32(0), new Uint32(0), new Uint32(1)]); }); it('Works on field elements', async () => { - machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(3), new Field(1)]); + context.machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(3), new Field(1)]); [ new Eq(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), new Eq(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 11), new Eq(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 3, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); expect(actual).toEqual([new Field(0), new Field(0), new Field(1)]); }); it('InTag is checked', async () => { - machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); + context.machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); const ops = [ new Eq(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), @@ -75,7 +70,7 @@ describe('Comparators', () => { ]; for (const o of ops) { - await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); + await expect(() => o.execute(context)).rejects.toThrow(TagCheckError); } }); }); @@ -103,33 +98,25 @@ describe('Comparators', () => { }); it('Works on integral types', async () => { - machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); + context.machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); [ new Lt(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), new Lt(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), new Lt(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); expect(actual).toEqual([new Uint32(0), new Uint32(1), new Uint32(0)]); }); - it('Works on field elements', async () => { - machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); - - [ - new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), - new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), - new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); - - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Field(0), new Field(1), new Field(0)]); + it('Does not work on field elements', async () => { + await expect(() => + new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10).execute(context), + ).rejects.toThrow(TagCheckError); }); - it('InTag is checked', async () => { - machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); + context.machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); const ops = [ new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), @@ -139,7 +126,7 @@ describe('Comparators', () => { ]; for (const o of ops) { - await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); + await expect(() => o.execute(context)).rejects.toThrow(TagCheckError); } }); }); @@ -167,33 +154,26 @@ describe('Comparators', () => { }); it('Works on integral types', async () => { - machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); + context.machineState.memory.setSlice(0, [new Uint32(1), new Uint32(2), new Uint32(0)]); [ new Lte(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), new Lte(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), new Lte(/*indirect=*/ 0, TypeTag.UINT32, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); expect(actual).toEqual([new Uint32(1), new Uint32(1), new Uint32(0)]); }); - it('Works on field elements', async () => { - machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); - - [ - new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), - new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), - new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), - ].forEach(i => i.execute(machineState, journal)); - - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Field(1), new Field(1), new Field(0)]); + it('Does not work on field elements', async () => { + await expect(() => + new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10).execute(context), + ).rejects.toThrow(TagCheckError); }); it('InTag is checked', async () => { - machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); + context.machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); const ops = [ new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10), @@ -203,7 +183,7 @@ describe('Comparators', () => { ]; for (const o of ops) { - await expect(() => o.execute(machineState, journal)).rejects.toThrow(InstructionExecutionError); + await expect(() => o.execute(context)).rejects.toThrow(TagCheckError); } }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.ts b/yarn-project/simulator/src/avm/opcodes/comparators.ts new file mode 100644 index 00000000000..cff0b9baa38 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/comparators.ts @@ -0,0 +1,72 @@ +import type { AvmContext } from '../avm_context.js'; +import { IntegralValue, TaggedMemory } from '../avm_memory_types.js'; +import { Opcode } from '../serialization/instruction_serialization.js'; +import { ThreeOperandInstruction } from './instruction_impl.js'; + +export class Eq extends ThreeOperandInstruction { + static readonly type: string = 'EQ'; + static readonly opcode = Opcode.EQ; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); + + // Result will be of the same type as 'a'. + const dest = a.build(a.equals(b) ? 1n : 0n); + context.machineState.memory.set(this.dstOffset, dest); + + context.machineState.incrementPc(); + } +} + +export class Lt extends ThreeOperandInstruction { + static readonly type: string = 'LT'; + static readonly opcode = Opcode.LT; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + TaggedMemory.checkIsIntegralTag(this.inTag); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + // Result will be of the same type as 'a'. + const dest = a.build(a.lt(b) ? 1n : 0n); + context.machineState.memory.set(this.dstOffset, dest); + + context.machineState.incrementPc(); + } +} + +export class Lte extends ThreeOperandInstruction { + static readonly type: string = 'LTE'; + static readonly opcode = Opcode.LTE; + + constructor(indirect: number, inTag: number, aOffset: number, bOffset: number, dstOffset: number) { + super(indirect, inTag, aOffset, bOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); + TaggedMemory.checkIsIntegralTag(this.inTag); + + const a = context.machineState.memory.getAs(this.aOffset); + const b = context.machineState.memory.getAs(this.bOffset); + + // Result will be of the same type as 'a'. + const dest = a.build(a.equals(b) || a.lt(b) ? 1n : 0n); + context.machineState.memory.set(this.dstOffset, dest); + + context.machineState.incrementPc(); + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts b/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts similarity index 69% rename from yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts rename to yarn-project/simulator/src/avm/opcodes/control_flow.test.ts index 82879c619b9..fee81ec3402 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/control_flow.test.ts @@ -1,21 +1,16 @@ import { Fr } from '@aztec/foundation/fields'; -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field, Uint16 } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; +import { InstructionExecutionError } from '../errors.js'; +import { initContext } from '../fixtures/index.js'; import { InternalCall, InternalReturn, Jump, JumpI, Return, Revert } from './control_flow.js'; -import { InstructionExecutionError } from './instruction.js'; describe('Control Flow Opcodes', () => { - let journal: MockProxy; - let machineState: AvmMachineState; + let context: AvmContext; beforeEach(() => { - journal = mock(); - machineState = new AvmMachineState(initExecutionEnvironment()); + context = initContext(); }); describe('JUMP', () => { @@ -33,11 +28,11 @@ describe('Control Flow Opcodes', () => { it('Should implement JUMP', async () => { const jumpLocation = 22; - expect(machineState.pc).toBe(0); + expect(context.machineState.pc).toBe(0); const instruction = new Jump(jumpLocation); - await instruction.execute(machineState, journal); - expect(machineState.pc).toBe(jumpLocation); + await instruction.execute(context); + expect(context.machineState.pc).toBe(jumpLocation); }); }); @@ -59,31 +54,31 @@ describe('Control Flow Opcodes', () => { const jumpLocation = 22; const jumpLocation1 = 69; - expect(machineState.pc).toBe(0); + expect(context.machineState.pc).toBe(0); - machineState.memory.set(0, new Uint16(1n)); - machineState.memory.set(1, new Uint16(2n)); + context.machineState.memory.set(0, new Uint16(1n)); + context.machineState.memory.set(1, new Uint16(2n)); const instruction = new JumpI(/*indirect=*/ 0, jumpLocation, /*condOffset=*/ 0); - await instruction.execute(machineState, journal); - expect(machineState.pc).toBe(jumpLocation); + await instruction.execute(context); + expect(context.machineState.pc).toBe(jumpLocation); // Truthy can be greater than 1 const instruction1 = new JumpI(/*indirect=*/ 0, jumpLocation1, /*condOffset=*/ 1); - await instruction1.execute(machineState, journal); - expect(machineState.pc).toBe(jumpLocation1); + await instruction1.execute(context); + expect(context.machineState.pc).toBe(jumpLocation1); }); it('Should implement JUMPI - falsy', async () => { const jumpLocation = 22; - expect(machineState.pc).toBe(0); + expect(context.machineState.pc).toBe(0); - machineState.memory.set(0, new Uint16(0n)); + context.machineState.memory.set(0, new Uint16(0n)); const instruction = new JumpI(/*indirect=*/ 0, jumpLocation, /*condOffset=*/ 0); - await instruction.execute(machineState, journal); - expect(machineState.pc).toBe(1); + await instruction.execute(context); + expect(context.machineState.pc).toBe(1); }); }); @@ -102,20 +97,20 @@ describe('Control Flow Opcodes', () => { it('Should implement Internal Call and Return', async () => { const jumpLocation = 22; - expect(machineState.pc).toBe(0); + expect(context.machineState.pc).toBe(0); const instruction = new InternalCall(jumpLocation); const returnInstruction = new InternalReturn(); - await instruction.execute(machineState, journal); - expect(machineState.pc).toBe(jumpLocation); + await instruction.execute(context); + expect(context.machineState.pc).toBe(jumpLocation); - await returnInstruction.execute(machineState, journal); - expect(machineState.pc).toBe(1); + await returnInstruction.execute(context); + expect(context.machineState.pc).toBe(1); }); it('Should error if Internal Return is called without a corresponding Internal Call', async () => { - const returnInstruction = () => new InternalReturn().execute(machineState, journal); + const returnInstruction = () => new InternalReturn().execute(context); await expect(returnInstruction()).rejects.toThrow(InstructionExecutionError); }); }); @@ -151,8 +146,8 @@ describe('Control Flow Opcodes', () => { ]; for (let i = 0; i < instructions.length; i++) { - await instructions[i].execute(machineState, journal); - expect(machineState.pc).toBe(expectedPcs[i]); + await instructions[i].execute(context); + expect(context.machineState.pc).toBe(expectedPcs[i]); } }); }); @@ -174,16 +169,18 @@ describe('Control Flow Opcodes', () => { it('Should return data from the return opcode', async () => { const returnData = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState.memory.set(0, new Field(1n)); - machineState.memory.set(1, new Field(2n)); - machineState.memory.set(2, new Field(3n)); + context.machineState.memory.set(0, new Field(1n)); + context.machineState.memory.set(1, new Field(2n)); + context.machineState.memory.set(2, new Field(3n)); const instruction = new Return(/*indirect=*/ 0, /*returnOffset=*/ 0, returnData.length); - await instruction.execute(machineState, journal); + await instruction.execute(context); - expect(machineState.getReturnData()).toEqual(returnData); - expect(machineState.halted).toBe(true); - expect(machineState.reverted).toBe(false); + expect(context.machineState.halted).toBe(true); + expect(context.machineState.getResults()).toEqual({ + reverted: false, + output: returnData, + }); }); }); @@ -204,16 +201,18 @@ describe('Control Flow Opcodes', () => { it('Should return data and revert from the revert opcode', async () => { const returnData = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState.memory.set(0, new Field(1n)); - machineState.memory.set(1, new Field(2n)); - machineState.memory.set(2, new Field(3n)); + context.machineState.memory.set(0, new Field(1n)); + context.machineState.memory.set(1, new Field(2n)); + context.machineState.memory.set(2, new Field(3n)); const instruction = new Revert(/*indirect=*/ 0, /*returnOffset=*/ 0, returnData.length); - await instruction.execute(machineState, journal); + await instruction.execute(context); - expect(machineState.getReturnData()).toEqual(returnData); - expect(machineState.halted).toBe(true); - expect(machineState.reverted).toBe(true); + expect(context.machineState.halted).toBe(true); + expect(context.machineState.getResults()).toEqual({ + reverted: true, + output: returnData, + }); }); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts b/yarn-project/simulator/src/avm/opcodes/control_flow.ts similarity index 67% rename from yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts rename to yarn-project/simulator/src/avm/opcodes/control_flow.ts index 1527a677116..a3a8faaf619 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/control_flow.ts +++ b/yarn-project/simulator/src/avm/opcodes/control_flow.ts @@ -1,8 +1,8 @@ -import { AvmMachineState } from '../avm_machine_state.js'; +import type { AvmContext } from '../avm_context.js'; import { IntegralValue } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/journal.js'; +import { InstructionExecutionError } from '../errors.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; -import { Instruction, InstructionExecutionError } from './instruction.js'; +import { Instruction } from './instruction.js'; export class Return extends Instruction { static type: string = 'RETURN'; @@ -19,12 +19,10 @@ export class Return extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const returnData = machineState.memory.getSlice(this.returnOffset, this.copySize).map(word => word.toFr()); + async execute(context: AvmContext): Promise { + const output = context.machineState.memory.getSlice(this.returnOffset, this.copySize).map(word => word.toFr()); - machineState.setReturnData(returnData); - - this.halt(machineState); + context.machineState.return(output); } } @@ -43,13 +41,12 @@ export class Revert extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const returnData = machineState.memory + async execute(context: AvmContext): Promise { + const output = context.machineState.memory .getSlice(this.returnOffset, this.returnOffset + this.retSize) .map(word => word.toFr()); - machineState.setReturnData(returnData); - this.revert(machineState); + context.machineState.revert(output); } } @@ -63,8 +60,8 @@ export class Jump extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - machineState.pc = this.jumpOffset; + async execute(context: AvmContext): Promise { + context.machineState.pc = this.jumpOffset; } } @@ -84,14 +81,14 @@ export class JumpI extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const condition = machineState.memory.getAs(this.condOffset); + async execute(context: AvmContext): Promise { + const condition = context.machineState.memory.getAs(this.condOffset); // TODO: reconsider this casting if (condition.toBigInt() == 0n) { - this.incrementPc(machineState); + context.machineState.incrementPc(); } else { - machineState.pc = this.loc; + context.machineState.pc = this.loc; } } } @@ -106,9 +103,9 @@ export class InternalCall extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - machineState.internalCallStack.push(machineState.pc + 1); - machineState.pc = this.loc; + async execute(context: AvmContext): Promise { + context.machineState.internalCallStack.push(context.machineState.pc + 1); + context.machineState.pc = this.loc; } } @@ -122,11 +119,11 @@ export class InternalReturn extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const jumpOffset = machineState.internalCallStack.pop(); + async execute(context: AvmContext): Promise { + const jumpOffset = context.machineState.internalCallStack.pop(); if (jumpOffset === undefined) { throw new InstructionExecutionError('Internal call empty!'); } - machineState.pc = jumpOffset; + context.machineState.pc = jumpOffset; } } diff --git a/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts b/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts new file mode 100644 index 00000000000..be9505d4e19 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/environment_getters.test.ts @@ -0,0 +1,92 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { initContext, initExecutionEnvironment, initGlobalVariables } from '../fixtures/index.js'; +import { + Address, + BlockNumber, + ChainId, + FeePerDAGas, + FeePerL1Gas, + FeePerL2Gas, + Origin, + Portal, + Sender, + StorageAddress, + Timestamp, + Version, +} from './environment_getters.js'; + +type EnvInstruction = + | typeof Portal + | typeof FeePerL1Gas + | typeof FeePerL2Gas + | typeof FeePerDAGas + | typeof Origin + | typeof Sender + | typeof StorageAddress + | typeof Address; +describe.each([ + [Portal, 'portal'], + [FeePerL1Gas, 'feePerL1Gas'], + [FeePerL2Gas, 'feePerL2Gas'], + [FeePerDAGas, 'feePerDaGas'], + [Origin, 'origin'], + [Sender, 'sender'], + [StorageAddress, 'storageAddress'], + [Address, 'address'], +])('Environment getters instructions', (clsValue: EnvInstruction, key: string) => { + it(`${clsValue.name} should (de)serialize correctly`, () => { + const buf = Buffer.from([ + clsValue.opcode, // opcode + 0x01, // indirect + ...Buffer.from('12345678', 'hex'), // dstOffset + ]); + const inst = new clsValue(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); + + expect(clsValue.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it(`${clsValue.name} should read '${key}' correctly`, async () => { + const value = new Fr(123456n); + const instruction = new clsValue(/*indirect=*/ 0, /*dstOffset=*/ 0); + const context = initContext({ env: initExecutionEnvironment({ [key]: value }) }); + + await instruction.execute(context); + + const actual = context.machineState.memory.get(0).toFr(); + expect(actual).toEqual(value); + }); +}); + +type GlobalsInstruction = typeof ChainId | typeof Version | typeof BlockNumber | typeof Timestamp; +describe.each([ + [ChainId, 'chainId'], + [Version, 'version'], + [BlockNumber, 'blockNumber'], + [Timestamp, 'timestamp'], +])('Global Variables', (clsValue: GlobalsInstruction, key: string) => { + it(`${clsValue.name} should (de)serialize correctly`, () => { + const buf = Buffer.from([ + clsValue.opcode, // opcode + 0x01, // indirect + ...Buffer.from('12345678', 'hex'), // dstOffset + ]); + const inst = new clsValue(/*indirect=*/ 0x01, /*dstOffset=*/ 0x12345678); + + expect(clsValue.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it(`${clsValue.name} should read '${key}' correctly`, async () => { + const value = new Fr(123456n); + const instruction = new clsValue(/*indirect=*/ 0, /*dstOffset=*/ 0); + const globals = initGlobalVariables({ [key]: value }); + const context = initContext({ env: initExecutionEnvironment({ globals }) }); + + await instruction.execute(context); + + const actual = context.machineState.memory.get(0).toFr(); + expect(actual).toEqual(value); + }); +}); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/environment_getters.ts b/yarn-project/simulator/src/avm/opcodes/environment_getters.ts similarity index 92% rename from yarn-project/acir-simulator/src/avm/opcodes/environment_getters.ts rename to yarn-project/simulator/src/avm/opcodes/environment_getters.ts index 8dc59330e94..35e2e29c4d9 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/environment_getters.ts +++ b/yarn-project/simulator/src/avm/opcodes/environment_getters.ts @@ -1,7 +1,6 @@ -import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; -import { AvmMachineState } from '../avm_machine_state.js'; +import type { AvmContext } from '../avm_context.js'; +import type { AvmExecutionEnvironment } from '../avm_execution_environment.js'; import { Field } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/journal.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; import { Instruction } from './instruction.js'; @@ -13,10 +12,10 @@ abstract class GetterInstruction extends Instruction { super(); } - async execute(machineState: AvmMachineState, _journal: AvmJournal): Promise { - const res = new Field(this.getIt(machineState.executionEnvironment)); - machineState.memory.set(this.dstOffset, res); - this.incrementPc(machineState); + async execute(context: AvmContext): Promise { + const res = new Field(this.getIt(context.environment)); + context.machineState.memory.set(this.dstOffset, res); + context.machineState.incrementPc(); } protected abstract getIt(env: AvmExecutionEnvironment): any; diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts similarity index 81% rename from yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts rename to yarn-project/simulator/src/avm/opcodes/external_calls.test.ts index 2395cc32479..a7b0bab2e69 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts @@ -1,14 +1,14 @@ import { Fr } from '@aztec/foundation/fields'; import { jest } from '@jest/globals'; -import { MockProxy, mock } from 'jest-mock-extended'; +import { mock } from 'jest-mock-extended'; import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; +import { initContext } from '../fixtures/index.js'; import { HostStorage } from '../journal/host_storage.js'; -import { AvmJournal } from '../journal/journal.js'; +import { AvmWorldStateJournal } from '../journal/journal.js'; import { encodeToBytecode } from '../serialization/bytecode_serialization.js'; import { Return } from './control_flow.js'; import { Call, StaticCall } from './external_calls.js'; @@ -17,20 +17,15 @@ import { CalldataCopy } from './memory.js'; import { SStore } from './storage.js'; describe('External Calls', () => { - let machineState: AvmMachineState; - let journal: AvmJournal; - - let contractsDb: MockProxy; + let context: AvmContext; beforeEach(() => { - machineState = new AvmMachineState(initExecutionEnvironment()); - - contractsDb = mock(); - + const contractsDb = mock(); const commitmentsDb = mock(); const publicStateDb = mock(); const hostStorage = new HostStorage(publicStateDb, contractsDb, commitmentsDb); - journal = new AvmJournal(hostStorage); + const journal = new AvmWorldStateJournal(hostStorage); + context = initContext({ worldState: journal }); }); describe('Call', () => { @@ -79,11 +74,11 @@ describe('External Calls', () => { new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2), ]); - machineState.memory.set(0, new Field(gas)); - machineState.memory.set(1, new Field(addr)); - machineState.memory.setSlice(2, args); + context.machineState.memory.set(0, new Field(gas)); + context.machineState.memory.set(1, new Field(addr)); + context.machineState.memory.setSlice(2, args); jest - .spyOn(journal.hostStorage.contractsDb, 'getBytecode') + .spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode') .mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); const instruction = new Call( @@ -96,16 +91,16 @@ describe('External Calls', () => { retSize, successOffset, ); - await instruction.execute(machineState, journal); + await instruction.execute(context); - const successValue = machineState.memory.get(successOffset); + const successValue = context.machineState.memory.get(successOffset); expect(successValue).toEqual(new Field(1n)); - const retValue = machineState.memory.getSlice(retOffset, retSize); + const retValue = context.machineState.memory.getSlice(retOffset, retSize); expect(retValue).toEqual([new Field(1n), new Field(2n)]); // Check that the storage call has been merged into the parent journal - const { currentStorageValue } = journal.flush(); + const { currentStorageValue } = context.worldState.flush(); expect(currentStorageValue.size).toEqual(1); const nestedContractWrites = currentStorageValue.get(addr.toBigInt()); @@ -158,9 +153,9 @@ describe('External Calls', () => { const retSize = 2; const successOffset = 7; - machineState.memory.set(0, gas); - machineState.memory.set(1, addr); - machineState.memory.setSlice(2, args); + context.machineState.memory.set(0, gas); + context.machineState.memory.set(1, addr); + context.machineState.memory.setSlice(2, args); const otherContextInstructions: Instruction[] = [ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), @@ -170,7 +165,7 @@ describe('External Calls', () => { const otherContextInstructionsBytecode = encodeToBytecode(otherContextInstructions); jest - .spyOn(journal.hostStorage.contractsDb, 'getBytecode') + .spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode') .mockReturnValue(Promise.resolve(otherContextInstructionsBytecode)); const instruction = new StaticCall( @@ -183,10 +178,10 @@ describe('External Calls', () => { retSize, successOffset, ); - await instruction.execute(machineState, journal); + await instruction.execute(context); // No revert has occurred, but the nested execution has failed - const successValue = machineState.memory.get(successOffset); + const successValue = context.machineState.memory.get(successOffset); expect(successValue).toEqual(new Field(0n)); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.ts similarity index 56% rename from yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts rename to yarn-project/simulator/src/avm/opcodes/external_calls.ts index 79b96891f72..8ff20f6b24a 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.ts @@ -1,9 +1,8 @@ import { Fr } from '@aztec/foundation/fields'; -import { AvmContext } from '../avm_context.js'; -import { AvmMachineState } from '../avm_machine_state.js'; +import type { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/journal.js'; +import { AvmSimulator } from '../avm_simulator.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; import { Instruction } from './instruction.js'; @@ -37,34 +36,30 @@ export class Call extends Instruction { } // TODO(https://github.com/AztecProtocol/aztec-packages/issues/3992): there is no concept of remaining / available gas at this moment - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - const callAddress = machineState.memory.getAs(this.addrOffset); - const calldata = machineState.memory.getSlice(this.argsOffset, this.argsSize).map(f => new Fr(f.toBigInt())); + async execute(context: AvmContext): Promise { + const callAddress = context.machineState.memory.getAs(this.addrOffset); + const calldata = context.machineState.memory.getSlice(this.argsOffset, this.argsSize).map(f => f.toFr()); - const avmContext = AvmContext.prepExternalCallContext( - new Fr(callAddress.toBigInt()), - calldata, - machineState.executionEnvironment, - journal, - ); + const nestedContext = context.createNestedContractCallContext(callAddress.toFr(), calldata); - const returnObject = await avmContext.call(); - const success = !returnObject.reverted; + const nestedCallResults = await new AvmSimulator(nestedContext).execute(); + const success = !nestedCallResults.reverted; // We only take as much data as was specified in the return size -> TODO: should we be reverting here - const returnData = returnObject.output.slice(0, this.retSize); + const returnData = nestedCallResults.output.slice(0, this.retSize); const convertedReturnData = returnData.map(f => new Field(f)); // Write our return data into memory - machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); - machineState.memory.setSlice(this.retOffset, convertedReturnData); + context.machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); + context.machineState.memory.setSlice(this.retOffset, convertedReturnData); if (success) { - avmContext.mergeJournalSuccess(); + context.worldState.acceptNestedWorldState(nestedContext.worldState); } else { - avmContext.mergeJournalFailure(); + context.worldState.rejectNestedWorldState(nestedContext.worldState); } - this.incrementPc(machineState); + + context.machineState.incrementPc(); } } @@ -97,34 +92,31 @@ export class StaticCall extends Instruction { super(); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - const callAddress = machineState.memory.get(this.addrOffset); - const calldata = machineState.memory.getSlice(this.argsOffset, this.argsSize).map(f => new Fr(f.toBigInt())); + async execute(context: AvmContext): Promise { + const callAddress = context.machineState.memory.get(this.addrOffset); + const calldata = context.machineState.memory + .getSlice(this.argsOffset, this.argsSize) + .map(f => new Fr(f.toBigInt())); - const avmContext = AvmContext.prepExternalStaticCallContext( - new Fr(callAddress.toBigInt()), - calldata, - machineState.executionEnvironment, - journal, - ); + const nestedContext = context.createNestedContractStaticCallContext(callAddress.toFr(), calldata); - const returnObject = await avmContext.call(); - const success = !returnObject.reverted; + const nestedCallResults = await new AvmSimulator(nestedContext).execute(); + const success = !nestedCallResults.reverted; // We only take as much data as was specified in the return size -> TODO: should we be reverting here - const returnData = returnObject.output.slice(0, this.retSize); + const returnData = nestedCallResults.output.slice(0, this.retSize); const convertedReturnData = returnData.map(f => new Field(f)); // Write our return data into memory - machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); - machineState.memory.setSlice(this.retOffset, convertedReturnData); + context.machineState.memory.set(this.successOffset, new Field(success ? 1 : 0)); + context.machineState.memory.setSlice(this.retOffset, convertedReturnData); if (success) { - avmContext.mergeJournalSuccess(); + context.worldState.acceptNestedWorldState(nestedContext.worldState); } else { - avmContext.mergeJournalFailure(); + context.worldState.rejectNestedWorldState(nestedContext.worldState); } - this.incrementPc(machineState); + context.machineState.incrementPc(); } } diff --git a/yarn-project/acir-simulator/src/avm/opcodes/index.ts b/yarn-project/simulator/src/avm/opcodes/index.ts similarity index 70% rename from yarn-project/acir-simulator/src/avm/opcodes/index.ts rename to yarn-project/simulator/src/avm/opcodes/index.ts index 2fa19f7b04a..d8dc52a8cf5 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/index.ts +++ b/yarn-project/simulator/src/avm/opcodes/index.ts @@ -5,7 +5,6 @@ export * from './instruction.js'; export * from './comparators.js'; export * from './memory.js'; export * from './storage.js'; -// TODO(https://github.com/AztecProtocol/aztec-packages/issues/4359): dependency cycle -// export * from './external_calls.js'; +export * from './external_calls.js'; export * from './environment_getters.js'; export * from './accrued_substate.js'; diff --git a/yarn-project/simulator/src/avm/opcodes/instruction.ts b/yarn-project/simulator/src/avm/opcodes/instruction.ts new file mode 100644 index 00000000000..afe7f6e5209 --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/instruction.ts @@ -0,0 +1,64 @@ +import { strict as assert } from 'assert'; + +import type { AvmContext } from '../avm_context.js'; +import { BufferCursor } from '../serialization/buffer_cursor.js'; +import { OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js'; + +type InstructionConstructor = { + new (...args: any[]): Instruction; + wireFormat?: OperandType[]; +}; + +/** + * Parent class for all AVM instructions. + * It's most important aspects are execute and (de)serialize. + */ +export abstract class Instruction { + /** + * Execute the instruction. + * Instruction sub-classes must implement this. + * As an AvmContext executes its contract code, it calls this function for + * each instruction until the machine state signals "halted". + * @param context - The AvmContext in which the instruction executes. + */ + public abstract execute(context: AvmContext): Promise; + + /** + * Generate a string representation of the instruction including + * the instruction sub-class name all of its flags and operands. + * @returns Thee string representation. + */ + public toString(): string { + let instructionStr = this.constructor.name + ': '; + // assumes that all properties are flags or operands + for (const prop of Object.getOwnPropertyNames(this) as (keyof Instruction)[]) { + instructionStr += `${prop}:${this[prop].toString()}, `; + } + return instructionStr; + } + + /** + * Serialize the instruction to a Buffer according to its wire format specified in its subclass. + * If you want to use this, your subclass should specify a {@code static wireFormat: OperandType[]}. + * @param this - The instruction to serialize. + * @returns The serialized instruction. + */ + public serialize(this: any): Buffer { + assert(!!this.constructor.wireFormat, 'wireFormat must be defined on the class'); + return serialize(this.constructor.wireFormat, this); + } + + /** + * Deserializes a subclass of Instruction from a Buffer. + * If you want to use this, your subclass should specify a {@code static wireFormat: OperandType[]}. + * @param this Class object to deserialize to. + * @param buf Buffer to read from. + * @returns Constructed instance of Class. + */ + public static deserialize(this: InstructionConstructor, buf: BufferCursor | Buffer): Instruction { + assert(!!this.wireFormat, 'wireFormat must be defined on the instruction class'); + const res = deserialize(buf, this.wireFormat); + const args = res.slice(1); // Remove opcode. + return new this(...args); + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/instruction_impl.ts b/yarn-project/simulator/src/avm/opcodes/instruction_impl.ts similarity index 100% rename from yarn-project/acir-simulator/src/avm/opcodes/instruction_impl.ts rename to yarn-project/simulator/src/avm/opcodes/instruction_impl.ts diff --git a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts b/yarn-project/simulator/src/avm/opcodes/memory.test.ts similarity index 54% rename from yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts rename to yarn-project/simulator/src/avm/opcodes/memory.test.ts index 438e7d9eadb..d7b691435a1 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/memory.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/memory.test.ts @@ -1,35 +1,97 @@ import { Fr } from '@aztec/foundation/fields'; -import { MockProxy, mock } from 'jest-mock-extended'; - -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field, TypeTag, Uint8, Uint16, Uint32, Uint64, Uint128 } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; -import { InstructionExecutionError } from './instruction.js'; +import { InstructionExecutionError } from '../errors.js'; +import { initContext, initExecutionEnvironment } from '../fixtures/index.js'; +import { Addressing, AddressingMode } from './addressing_mode.js'; import { CMov, CalldataCopy, Cast, Mov, Set } from './memory.js'; describe('Memory instructions', () => { - let machineState: AvmMachineState; - let journal: MockProxy; + let context: AvmContext; - beforeEach(async () => { - machineState = new AvmMachineState(initExecutionEnvironment()); - journal = mock(); + beforeEach(() => { + context = initContext(); }); describe('SET', () => { - it('Should (de)serialize correctly', () => { + it('Should (de)serialize correctly [tag=u8]', () => { + const buf = Buffer.from([ + Set.opcode, // opcode + 0x01, // indirect + TypeTag.UINT8, // inTag + ...Buffer.from('12', 'hex'), + ...Buffer.from('3456789a', 'hex'), // dstOffset + ]); + const inst = new Set(/*indirect=*/ 0x01, /*inTag=*/ TypeTag.UINT8, /*value=*/ 0x12, /*dstOffset=*/ 0x3456789a); + + expect(Set.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should (de)serialize correctly [tag=u16]', () => { const buf = Buffer.from([ Set.opcode, // opcode 0x01, // indirect - TypeTag.FIELD, // inTag + TypeTag.UINT16, // inTag + ...Buffer.from('1234', 'hex'), + ...Buffer.from('3456789a', 'hex'), // dstOffset + ]); + const inst = new Set(/*indirect=*/ 0x01, /*inTag=*/ TypeTag.UINT16, /*value=*/ 0x1234, /*dstOffset=*/ 0x3456789a); + + expect(Set.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should (de)serialize correctly [tag=u32]', () => { + const buf = Buffer.from([ + Set.opcode, // opcode + 0x01, // indirect + TypeTag.UINT32, // inTag + ...Buffer.from('12345678', 'hex'), + ...Buffer.from('3456789a', 'hex'), // dstOffset + ]); + const inst = new Set( + /*indirect=*/ 0x01, + /*inTag=*/ TypeTag.UINT32, + /*value=*/ 0x12345678, + /*dstOffset=*/ 0x3456789a, + ); + + expect(Set.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should (de)serialize correctly [tag=u64]', () => { + const buf = Buffer.from([ + Set.opcode, // opcode + 0x01, // indirect + TypeTag.UINT64, // inTag + ...Buffer.from('1234567812345678', 'hex'), + ...Buffer.from('3456789a', 'hex'), // dstOffset + ]); + const inst = new Set( + /*indirect=*/ 0x01, + /*inTag=*/ TypeTag.UINT64, + /*value=*/ 0x1234567812345678n, + /*dstOffset=*/ 0x3456789a, + ); + + expect(Set.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should (de)serialize correctly [tag=u128]', () => { + const buf = Buffer.from([ + Set.opcode, // opcode + 0x01, // indirect + TypeTag.UINT128, // inTag ...Buffer.from('12345678123456781234567812345678', 'hex'), // const (will be 128 bit) ...Buffer.from('3456789a', 'hex'), // dstOffset ]); const inst = new Set( /*indirect=*/ 0x01, - /*inTag=*/ TypeTag.FIELD, + /*inTag=*/ TypeTag.UINT128, /*value=*/ 0x12345678123456781234567812345678n, /*dstOffset=*/ 0x3456789a, ); @@ -39,41 +101,32 @@ describe('Memory instructions', () => { }); it('should correctly set value and tag (uninitialized)', async () => { - await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*value=*/ 1234n, /*offset=*/ 1).execute( - machineState, - journal, - ); + await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*value=*/ 1234n, /*offset=*/ 1).execute(context); - const actual = machineState.memory.get(1); - const tag = machineState.memory.getTag(1); + const actual = context.machineState.memory.get(1); + const tag = context.machineState.memory.getTag(1); expect(actual).toEqual(new Uint16(1234n)); expect(tag).toEqual(TypeTag.UINT16); }); it('should correctly set value and tag (overwriting)', async () => { - machineState.memory.set(1, new Field(27)); + context.machineState.memory.set(1, new Field(27)); - await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT32, /*value=*/ 1234n, /*offset=*/ 1).execute( - machineState, - journal, - ); + await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT32, /*value=*/ 1234n, /*offset=*/ 1).execute(context); - const actual = machineState.memory.get(1); - const tag = machineState.memory.getTag(1); + const actual = context.machineState.memory.get(1); + const tag = context.machineState.memory.getTag(1); expect(actual).toEqual(new Uint32(1234n)); expect(tag).toEqual(TypeTag.UINT32); }); it('should correctly set value and tag (truncating)', async () => { - await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*value=*/ 0x12345678n, /*offset=*/ 1).execute( - machineState, - journal, - ); + await new Set(/*indirect=*/ 0, /*inTag=*/ TypeTag.UINT16, /*value=*/ 0x12345678n, /*offset=*/ 1).execute(context); - const actual = machineState.memory.get(1); - const tag = machineState.memory.getTag(1); + const actual = context.machineState.memory.get(1); + const tag = context.machineState.memory.getTag(1); expect(actual).toEqual(new Uint16(0x5678)); expect(tag).toEqual(TypeTag.UINT16); @@ -82,7 +135,7 @@ describe('Memory instructions', () => { it('should throw if tag is FIELD, UNINITIALIZED, INVALID', async () => { for (const tag of [TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID]) { await expect( - new Set(/*indirect=*/ 0, /*inTag=*/ tag, /*value=*/ 1234n, /*offset=*/ 1).execute(machineState, journal), + new Set(/*indirect=*/ 0, /*inTag=*/ tag, /*value=*/ 1234n, /*offset=*/ 1).execute(context), ).rejects.toThrow(InstructionExecutionError); } }); @@ -109,11 +162,11 @@ describe('Memory instructions', () => { }); it('Should upcast between integral types', () => { - machineState.memory.set(0, new Uint8(20n)); - machineState.memory.set(1, new Uint16(65000n)); - machineState.memory.set(2, new Uint32(1n << 30n)); - machineState.memory.set(3, new Uint64(1n << 50n)); - machineState.memory.set(4, new Uint128(1n << 100n)); + context.machineState.memory.set(0, new Uint8(20n)); + context.machineState.memory.set(1, new Uint16(65000n)); + context.machineState.memory.set(2, new Uint32(1n << 30n)); + context.machineState.memory.set(3, new Uint64(1n << 50n)); + context.machineState.memory.set(4, new Uint128(1n << 100n)); [ new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT16, /*aOffset=*/ 0, /*dstOffset=*/ 10), @@ -121,9 +174,9 @@ describe('Memory instructions', () => { new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT64, /*aOffset=*/ 2, /*dstOffset=*/ 12), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT128, /*aOffset=*/ 3, /*dstOffset=*/ 13), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT128, /*aOffset=*/ 4, /*dstOffset=*/ 14), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ new Uint16(20n), new Uint32(65000n), @@ -131,16 +184,16 @@ describe('Memory instructions', () => { new Uint128(1n << 50n), new Uint128(1n << 100n), ]); - const tags = machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); + const tags = context.machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); expect(tags).toEqual([TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128, TypeTag.UINT128]); }); it('Should downcast (truncating) between integral types', () => { - machineState.memory.set(0, new Uint8(20n)); - machineState.memory.set(1, new Uint16(65000n)); - machineState.memory.set(2, new Uint32((1n << 30n) - 1n)); - machineState.memory.set(3, new Uint64((1n << 50n) - 1n)); - machineState.memory.set(4, new Uint128((1n << 100n) - 1n)); + context.machineState.memory.set(0, new Uint8(20n)); + context.machineState.memory.set(1, new Uint16(65000n)); + context.machineState.memory.set(2, new Uint32((1n << 30n) - 1n)); + context.machineState.memory.set(3, new Uint64((1n << 50n) - 1n)); + context.machineState.memory.set(4, new Uint128((1n << 100n) - 1n)); [ new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT8, /*aOffset=*/ 0, /*dstOffset=*/ 10), @@ -148,9 +201,9 @@ describe('Memory instructions', () => { new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT16, /*aOffset=*/ 2, /*dstOffset=*/ 12), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT32, /*aOffset=*/ 3, /*dstOffset=*/ 13), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT64, /*aOffset=*/ 4, /*dstOffset=*/ 14), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ new Uint8(20n), new Uint8(232), @@ -158,26 +211,25 @@ describe('Memory instructions', () => { new Uint32((1n << 32n) - 1n), new Uint64((1n << 64n) - 1n), ]); - const tags = machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); + const tags = context.machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); expect(tags).toEqual([TypeTag.UINT8, TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64]); }); it('Should upcast from integral types to field', () => { - machineState.memory.set(0, new Uint8(20n)); - machineState.memory.set(1, new Uint16(65000n)); - machineState.memory.set(2, new Uint32(1n << 30n)); - machineState.memory.set(3, new Uint64(1n << 50n)); - machineState.memory.set(4, new Uint128(1n << 100n)); - + context.machineState.memory.set(0, new Uint8(20n)); + context.machineState.memory.set(1, new Uint16(65000n)); + context.machineState.memory.set(2, new Uint32(1n << 30n)); + context.machineState.memory.set(3, new Uint64(1n << 50n)); + context.machineState.memory.set(4, new Uint128(1n << 100n)); [ new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 0, /*dstOffset=*/ 10), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 1, /*dstOffset=*/ 11), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 2, /*dstOffset=*/ 12), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 3, /*dstOffset=*/ 13), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 4, /*dstOffset=*/ 14), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ new Field(20n), new Field(65000n), @@ -185,16 +237,16 @@ describe('Memory instructions', () => { new Field(1n << 50n), new Field(1n << 100n), ]); - const tags = machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); + const tags = context.machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); expect(tags).toEqual([TypeTag.FIELD, TypeTag.FIELD, TypeTag.FIELD, TypeTag.FIELD, TypeTag.FIELD]); }); it('Should downcast (truncating) from field to integral types', () => { - machineState.memory.set(0, new Field((1n << 200n) - 1n)); - machineState.memory.set(1, new Field((1n << 200n) - 1n)); - machineState.memory.set(2, new Field((1n << 200n) - 1n)); - machineState.memory.set(3, new Field((1n << 200n) - 1n)); - machineState.memory.set(4, new Field((1n << 200n) - 1n)); + context.machineState.memory.set(0, new Field((1n << 200n) - 1n)); + context.machineState.memory.set(1, new Field((1n << 200n) - 1n)); + context.machineState.memory.set(2, new Field((1n << 200n) - 1n)); + context.machineState.memory.set(3, new Field((1n << 200n) - 1n)); + context.machineState.memory.set(4, new Field((1n << 200n) - 1n)); [ new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT8, /*aOffset=*/ 0, /*dstOffset=*/ 10), @@ -202,9 +254,9 @@ describe('Memory instructions', () => { new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT32, /*aOffset=*/ 2, /*dstOffset=*/ 12), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT64, /*aOffset=*/ 3, /*dstOffset=*/ 13), new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.UINT128, /*aOffset=*/ 4, /*dstOffset=*/ 14), - ].forEach(i => i.execute(machineState, journal)); + ].forEach(i => i.execute(context)); - const actual = machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 5); expect(actual).toEqual([ new Uint8((1n << 8n) - 1n), new Uint16((1n << 16n) - 1n), @@ -212,21 +264,18 @@ describe('Memory instructions', () => { new Uint64((1n << 64n) - 1n), new Uint128((1n << 128n) - 1n), ]); - const tags = machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); + const tags = context.machineState.memory.getSliceTags(/*offset=*/ 10, /*size=*/ 5); expect(tags).toEqual([TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128]); }); it('Should cast between field elements', async () => { - machineState.memory.set(0, new Field(12345678n)); + context.machineState.memory.set(0, new Field(12345678n)); - await new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 0, /*dstOffset=*/ 1).execute( - machineState, - journal, - ); + await new Cast(/*indirect=*/ 0, /*dstTag=*/ TypeTag.FIELD, /*aOffset=*/ 0, /*dstOffset=*/ 1).execute(context); - const actual = machineState.memory.get(1); + const actual = context.machineState.memory.get(1); expect(actual).toEqual(new Field(12345678n)); - const tags = machineState.memory.getTag(1); + const tags = context.machineState.memory.getTag(1); expect(tags).toEqual(TypeTag.FIELD); }); }); @@ -246,22 +295,32 @@ describe('Memory instructions', () => { }); it('Should move integrals on different memory cells', async () => { - machineState.memory.set(0, new Uint16(27)); - await new Mov(/*indirect=*/ 0, /*srcOffset=*/ 0, /*dstOffset=*/ 1).execute(machineState, journal); + context.machineState.memory.set(0, new Uint16(27)); + await new Mov(/*indirect=*/ 0, /*srcOffset=*/ 0, /*dstOffset=*/ 1).execute(context); - const actual = machineState.memory.get(1); - const tag = machineState.memory.getTag(1); + const actual = context.machineState.memory.get(1); + const tag = context.machineState.memory.getTag(1); expect(actual).toEqual(new Uint16(27n)); expect(tag).toEqual(TypeTag.UINT16); }); + it('Should support INDIRECT addressing', async () => { + context.machineState.memory.set(0, new Uint16(55)); + context.machineState.memory.set(10, new Uint32(20)); + const addressing = new Addressing([/*srcOffset*/ AddressingMode.DIRECT, /*dstOffset*/ AddressingMode.INDIRECT]); + await new Mov(/*indirect=*/ addressing.toWire(), /*srcOffset=*/ 0, /*dstOffset=*/ 10).execute(context); + + expect(context.machineState.memory.get(1)).toBeUndefined(); + expect(context.machineState.memory.get(20)).toEqual(new Uint16(55n)); + }); + it('Should move field elements on different memory cells', async () => { - machineState.memory.set(0, new Field(27)); - await new Mov(/*indirect=*/ 0, /*srcOffset=*/ 0, /*dstOffset=*/ 1).execute(machineState, journal); + context.machineState.memory.set(0, new Field(27)); + await new Mov(/*indirect=*/ 0, /*srcOffset=*/ 0, /*dstOffset=*/ 1).execute(context); - const actual = machineState.memory.get(1); - const tag = machineState.memory.getTag(1); + const actual = context.machineState.memory.get(1); + const tag = context.machineState.memory.getTag(1); expect(actual).toEqual(new Field(27n)); expect(tag).toEqual(TypeTag.FIELD); @@ -291,65 +350,61 @@ describe('Memory instructions', () => { }); it('Should move A if COND is true, on different memory cells (integral condition)', async () => { - machineState.memory.set(0, new Uint32(123)); // A - machineState.memory.set(1, new Uint16(456)); // B - machineState.memory.set(2, new Uint8(2)); // Condition + context.machineState.memory.set(0, new Uint32(123)); // A + context.machineState.memory.set(1, new Uint16(456)); // B + context.machineState.memory.set(2, new Uint8(2)); // Condition await new CMov(/*indirect=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( - machineState, - journal, + context, ); - const actual = machineState.memory.get(3); - const tag = machineState.memory.getTag(3); + const actual = context.machineState.memory.get(3); + const tag = context.machineState.memory.getTag(3); expect(actual).toEqual(new Uint32(123)); expect(tag).toEqual(TypeTag.UINT32); }); it('Should move B if COND is false, on different memory cells (integral condition)', async () => { - machineState.memory.set(0, new Uint32(123)); // A - machineState.memory.set(1, new Uint16(456)); // B - machineState.memory.set(2, new Uint8(0)); // Condition + context.machineState.memory.set(0, new Uint32(123)); // A + context.machineState.memory.set(1, new Uint16(456)); // B + context.machineState.memory.set(2, new Uint8(0)); // Condition await new CMov(/*indirect=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( - machineState, - journal, + context, ); - const actual = machineState.memory.get(3); - const tag = machineState.memory.getTag(3); + const actual = context.machineState.memory.get(3); + const tag = context.machineState.memory.getTag(3); expect(actual).toEqual(new Uint16(456)); expect(tag).toEqual(TypeTag.UINT16); }); it('Should move A if COND is true, on different memory cells (field condition)', async () => { - machineState.memory.set(0, new Uint32(123)); // A - machineState.memory.set(1, new Uint16(456)); // B - machineState.memory.set(2, new Field(1)); // Condition + context.machineState.memory.set(0, new Uint32(123)); // A + context.machineState.memory.set(1, new Uint16(456)); // B + context.machineState.memory.set(2, new Field(1)); // Condition await new CMov(/*indirect=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( - machineState, - journal, + context, ); - const actual = machineState.memory.get(3); - const tag = machineState.memory.getTag(3); + const actual = context.machineState.memory.get(3); + const tag = context.machineState.memory.getTag(3); expect(actual).toEqual(new Uint32(123)); expect(tag).toEqual(TypeTag.UINT32); }); it('Should move B if COND is false, on different memory cells (integral condition)', async () => { - machineState.memory.set(0, new Uint32(123)); // A - machineState.memory.set(1, new Uint16(456)); // B - machineState.memory.set(2, new Field(0)); // Condition + context.machineState.memory.set(0, new Uint32(123)); // A + context.machineState.memory.set(1, new Uint16(456)); // B + context.machineState.memory.set(2, new Field(0)); // Condition await new CMov(/*indirect=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*condOffset=*/ 2, /*dstOffset=*/ 3).execute( - machineState, - journal, + context, ); - const actual = machineState.memory.get(3); - const tag = machineState.memory.getTag(3); + const actual = context.machineState.memory.get(3); + const tag = context.machineState.memory.getTag(3); expect(actual).toEqual(new Uint16(456)); expect(tag).toEqual(TypeTag.UINT16); }); @@ -377,43 +432,34 @@ describe('Memory instructions', () => { it('Writes nothing if size is 0', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten + context = initContext({ env: initExecutionEnvironment({ calldata }) }); + context.machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 0, /*dstOffset=*/ 0).execute( - machineState, - journal, - ); + await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 0, /*dstOffset=*/ 0).execute(context); - const actual = machineState.memory.get(0); + const actual = context.machineState.memory.get(0); expect(actual).toEqual(new Uint16(12)); }); it('Copies all calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten + context = initContext({ env: initExecutionEnvironment({ calldata }) }); + context.machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute( - machineState, - journal, - ); + await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 0, /*copySize=*/ 3, /*dstOffset=*/ 0).execute(context); - const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 3); + const actual = context.machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 3); expect(actual).toEqual([new Field(1), new Field(2), new Field(3)]); }); it('Copies slice of calldata', async () => { const calldata = [new Fr(1n), new Fr(2n), new Fr(3n)]; - machineState = new AvmMachineState(initExecutionEnvironment({ calldata })); - machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten + context = initContext({ env: initExecutionEnvironment({ calldata }) }); + context.machineState.memory.set(0, new Uint16(12)); // Some previous data to be overwritten - await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute( - machineState, - journal, - ); + await new CalldataCopy(/*indirect=*/ 0, /*cdOffset=*/ 1, /*copySize=*/ 2, /*dstOffset=*/ 0).execute(context); - const actual = machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 2); + const actual = context.machineState.memory.getSlice(/*offset=*/ 0, /*size=*/ 2); expect(actual).toEqual([new Field(2), new Field(3)]); }); diff --git a/yarn-project/simulator/src/avm/opcodes/memory.ts b/yarn-project/simulator/src/avm/opcodes/memory.ts new file mode 100644 index 00000000000..d8c9ad7c0ae --- /dev/null +++ b/yarn-project/simulator/src/avm/opcodes/memory.ts @@ -0,0 +1,193 @@ +import type { AvmContext } from '../avm_context.js'; +import { Field, TaggedMemory, TypeTag } from '../avm_memory_types.js'; +import { InstructionExecutionError } from '../errors.js'; +import { BufferCursor } from '../serialization/buffer_cursor.js'; +import { Opcode, OperandType, deserialize, serialize } from '../serialization/instruction_serialization.js'; +import { Addressing } from './addressing_mode.js'; +import { Instruction } from './instruction.js'; +import { TwoOperandInstruction } from './instruction_impl.js'; + +const TAG_TO_OPERAND_TYPE = new Map([ + [TypeTag.UINT8, OperandType.UINT8], + [TypeTag.UINT16, OperandType.UINT16], + [TypeTag.UINT32, OperandType.UINT32], + [TypeTag.UINT64, OperandType.UINT64], + [TypeTag.UINT128, OperandType.UINT128], +]); + +function getOperandTypeFromInTag(inTag: number | bigint): OperandType { + inTag = inTag as number; + const tagOperandType = TAG_TO_OPERAND_TYPE.get(inTag); + if (tagOperandType === undefined) { + throw new Error(`Invalid tag ${inTag} for SET.`); + } + return tagOperandType; +} + +export class Set extends Instruction { + static readonly type: string = 'SET'; + static readonly opcode: Opcode = Opcode.SET; + + private static readonly wireFormatBeforeConst: OperandType[] = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT8, + ]; + private static readonly wireFormatAfterConst: OperandType[] = [OperandType.UINT32]; + + constructor( + private indirect: number, + private inTag: number, + private value: bigint | number, + private dstOffset: number, + ) { + super(); + } + + /** We need to use a custom serialize function because of the variable length of the value. */ + public serialize(): Buffer { + const format: OperandType[] = [ + ...Set.wireFormatBeforeConst, + getOperandTypeFromInTag(this.inTag), + ...Set.wireFormatAfterConst, + ]; + return serialize(format, this); + } + + /** We need to use a custom deserialize function because of the variable length of the value. */ + public static deserialize(this: typeof Set, buf: BufferCursor | Buffer): Set { + if (buf instanceof Buffer) { + buf = new BufferCursor(buf); + } + const beforeConst = deserialize(buf, Set.wireFormatBeforeConst); + const tag = beforeConst[beforeConst.length - 1]; + const val = deserialize(buf, [getOperandTypeFromInTag(tag)]); + const afterConst = deserialize(buf, Set.wireFormatAfterConst); + const res = [...beforeConst, ...val, ...afterConst]; + const args = res.slice(1) as ConstructorParameters; // Remove opcode. + return new this(...args); + } + + async execute(context: AvmContext): Promise { + // Per the YP, the tag cannot be a field. + if ([TypeTag.FIELD, TypeTag.UNINITIALIZED, TypeTag.INVALID].includes(this.inTag)) { + throw new InstructionExecutionError(`Invalid tag ${TypeTag[this.inTag]} for SET.`); + } + + const res = TaggedMemory.integralFromTag(this.value, this.inTag); + context.machineState.memory.set(this.dstOffset, res); + + context.machineState.incrementPc(); + } +} + +export class CMov extends Instruction { + static readonly type: string = 'CMOV'; + static readonly opcode: Opcode = Opcode.CMOV; + // Informs (de)serialization. See Instruction.deserialize. + static readonly wireFormat: OperandType[] = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + ]; + + constructor( + private indirect: number, + private aOffset: number, + private bOffset: number, + private condOffset: number, + private dstOffset: number, + ) { + super(); + } + + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); + const cond = context.machineState.memory.get(this.condOffset); + + // TODO: reconsider toBigInt() here + context.machineState.memory.set(this.dstOffset, cond.toBigInt() > 0 ? a : b); + + context.machineState.incrementPc(); + } +} + +export class Cast extends TwoOperandInstruction { + static readonly type: string = 'CAST'; + static readonly opcode = Opcode.CAST; + + constructor(indirect: number, dstTag: number, aOffset: number, dstOffset: number) { + super(indirect, dstTag, aOffset, dstOffset); + } + + async execute(context: AvmContext): Promise { + const a = context.machineState.memory.get(this.aOffset); + + // TODO: consider not using toBigInt() + const casted = + this.inTag == TypeTag.FIELD ? new Field(a.toBigInt()) : TaggedMemory.integralFromTag(a.toBigInt(), this.inTag); + + context.machineState.memory.set(this.dstOffset, casted); + + context.machineState.incrementPc(); + } +} + +export class Mov extends Instruction { + static readonly type: string = 'MOV'; + static readonly opcode: Opcode = Opcode.MOV; + // Informs (de)serialization. See Instruction.deserialize. + static readonly wireFormat: OperandType[] = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + ]; + + constructor(private indirect: number, private srcOffset: number, private dstOffset: number) { + super(); + } + + async execute(context: AvmContext): Promise { + const [srcOffset, dstOffset] = Addressing.fromWire(this.indirect).resolve( + [this.srcOffset, this.dstOffset], + context.machineState.memory, + ); + + const a = context.machineState.memory.get(srcOffset); + + context.machineState.memory.set(dstOffset, a); + + context.machineState.incrementPc(); + } +} + +export class CalldataCopy extends Instruction { + static readonly type: string = 'CALLDATACOPY'; + static readonly opcode: Opcode = Opcode.CALLDATACOPY; + // Informs (de)serialization. See Instruction.deserialize. + static readonly wireFormat: OperandType[] = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + ]; + + constructor(private indirect: number, private cdOffset: number, private copySize: number, private dstOffset: number) { + super(); + } + + async execute(context: AvmContext): Promise { + const transformedData = context.environment.calldata + .slice(this.cdOffset, this.cdOffset + this.copySize) + .map(f => new Field(f)); + context.machineState.memory.setSlice(this.dstOffset, transformedData); + + context.machineState.incrementPc(); + } +} diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts b/yarn-project/simulator/src/avm/opcodes/storage.test.ts similarity index 68% rename from yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts rename to yarn-project/simulator/src/avm/opcodes/storage.test.ts index 8f704b036a3..dde14ba639c 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.test.ts @@ -3,22 +3,20 @@ import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; -import { AvmMachineState } from '../avm_machine_state.js'; +import { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; -import { initExecutionEnvironment } from '../fixtures/index.js'; -import { AvmJournal } from '../journal/journal.js'; +import { initContext, initExecutionEnvironment } from '../fixtures/index.js'; +import { AvmWorldStateJournal } from '../journal/journal.js'; import { SLoad, SStore, StaticCallStorageAlterError } from './storage.js'; describe('Storage Instructions', () => { - let journal: MockProxy; - let machineState: AvmMachineState; + let context: AvmContext; + let journal: MockProxy; const address = AztecAddress.random(); - beforeEach(() => { - journal = mock(); - - const executionEnvironment = initExecutionEnvironment({ address, storageAddress: address }); - machineState = new AvmMachineState(executionEnvironment); + beforeEach(async () => { + journal = mock(); + context = initContext({ worldState: journal, env: initExecutionEnvironment({ address, storageAddress: address }) }); }); describe('SSTORE', () => { @@ -39,26 +37,27 @@ describe('Storage Instructions', () => { const a = new Field(1n); const b = new Field(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); - await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(machineState, journal); + await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); expect(journal.writeStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); it('Should not be able to write to storage in a static call', async () => { - const executionEnvironment = initExecutionEnvironment({ isStaticCall: true }); - machineState = new AvmMachineState(executionEnvironment); + context = initContext({ + worldState: journal, + env: initExecutionEnvironment({ address, storageAddress: address, isStaticCall: true }), + }); const a = new Field(1n); const b = new Field(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); - const instruction = () => - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(machineState, journal); + const instruction = () => new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); await expect(instruction()).rejects.toThrow(StaticCallStorageAlterError); }); }); @@ -85,14 +84,14 @@ describe('Storage Instructions', () => { const a = new Field(1n); const b = new Field(2n); - machineState.memory.set(0, a); - machineState.memory.set(1, b); + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); - await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1).execute(machineState, journal); + await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1).execute(context); expect(journal.readStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt())); - const actual = machineState.memory.get(1); + const actual = context.machineState.memory.get(1); expect(actual).toEqual(new Field(expectedResult)); }); }); diff --git a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts b/yarn-project/simulator/src/avm/opcodes/storage.ts similarity index 61% rename from yarn-project/acir-simulator/src/avm/opcodes/storage.ts rename to yarn-project/simulator/src/avm/opcodes/storage.ts index 5cd9bee9ceb..3d59c5c57c6 100644 --- a/yarn-project/acir-simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.ts @@ -1,10 +1,10 @@ import { Fr } from '@aztec/foundation/fields'; -import { AvmMachineState } from '../avm_machine_state.js'; +import type { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; -import { AvmJournal } from '../journal/journal.js'; +import { InstructionExecutionError } from '../errors.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; -import { Instruction, InstructionExecutionError } from './instruction.js'; +import { Instruction } from './instruction.js'; abstract class BaseStorageInstruction extends Instruction { // Informs (de)serialization. See Instruction.deserialize. @@ -28,21 +28,21 @@ export class SStore extends BaseStorageInstruction { super(indirect, srcOffset, slotOffset); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - if (machineState.executionEnvironment.isStaticCall) { + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { throw new StaticCallStorageAlterError(); } - const slot = machineState.memory.get(this.aOffset); - const data = machineState.memory.get(this.bOffset); + const slot = context.machineState.memory.get(this.aOffset); + const data = context.machineState.memory.get(this.bOffset); - journal.writeStorage( - machineState.executionEnvironment.storageAddress, + context.worldState.writeStorage( + context.environment.storageAddress, new Fr(slot.toBigInt()), new Fr(data.toBigInt()), ); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } @@ -54,17 +54,14 @@ export class SLoad extends BaseStorageInstruction { super(indirect, slotOffset, dstOffset); } - async execute(machineState: AvmMachineState, journal: AvmJournal): Promise { - const slot = machineState.memory.get(this.aOffset); + async execute(context: AvmContext): Promise { + const slot = context.machineState.memory.get(this.aOffset); - const data: Fr = await journal.readStorage( - machineState.executionEnvironment.storageAddress, - new Fr(slot.toBigInt()), - ); + const data: Fr = await context.worldState.readStorage(context.environment.storageAddress, new Fr(slot.toBigInt())); - machineState.memory.set(this.bOffset, new Field(data)); + context.machineState.memory.set(this.bOffset, new Field(data)); - this.incrementPc(machineState); + context.machineState.incrementPc(); } } diff --git a/yarn-project/acir-simulator/src/avm/serialization/buffer_cursor.ts b/yarn-project/simulator/src/avm/serialization/buffer_cursor.ts similarity index 100% rename from yarn-project/acir-simulator/src/avm/serialization/buffer_cursor.ts rename to yarn-project/simulator/src/avm/serialization/buffer_cursor.ts diff --git a/yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.test.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.test.ts similarity index 69% rename from yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.test.ts rename to yarn-project/simulator/src/avm/serialization/bytecode_serialization.test.ts index adca61ef609..26e75171b65 100644 --- a/yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.test.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.test.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; -import { Add, Address, Sub } from '../opcodes/index.js'; +import { Add, Address, Call, StaticCall, Sub } from '../opcodes/index.js'; import { BufferCursor } from './buffer_cursor.js'; import { InstructionSet, decodeFromBytecode, encodeToBytecode } from './bytecode_serialization.js'; import { Opcode } from './instruction_serialization.js'; @@ -75,6 +75,26 @@ describe('Bytecode Serialization', () => { new Add(/*indirect=*/ 0, /*inTag=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), new Sub(/*indirect=*/ 0, /*inTag=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), new Address(/*indirect=*/ 0, /*dstOffset=*/ 1), + new Call( + /*indirect=*/ 0x01, + /*gasOffset=*/ 0x12345678, + /*addrOffset=*/ 0xa2345678, + /*argsOffset=*/ 0xb2345678, + /*argsSize=*/ 0xc2345678, + /*retOffset=*/ 0xd2345678, + /*retSize=*/ 0xe2345678, + /*successOffset=*/ 0xf2345678, + ), + new StaticCall( + /*indirect=*/ 0x01, + /*gasOffset=*/ 0x12345678, + /*addrOffset=*/ 0xa2345678, + /*argsOffset=*/ 0xb2345678, + /*argsSize=*/ 0xc2345678, + /*retOffset=*/ 0xd2345678, + /*retSize=*/ 0xe2345678, + /*successOffset=*/ 0xf2345678, + ), ]; const bytecode = Buffer.concat(instructions.map(i => i.serialize())); @@ -88,6 +108,26 @@ describe('Bytecode Serialization', () => { new Add(/*indirect=*/ 0, /*inTag=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), new Sub(/*indirect=*/ 0, /*inTag=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2), new Address(/*indirect=*/ 0, /*dstOffset=*/ 1), + new Call( + /*indirect=*/ 0x01, + /*gasOffset=*/ 0x12345678, + /*addrOffset=*/ 0xa2345678, + /*argsOffset=*/ 0xb2345678, + /*argsSize=*/ 0xc2345678, + /*retOffset=*/ 0xd2345678, + /*retSize=*/ 0xe2345678, + /*successOffset=*/ 0xf2345678, + ), + new StaticCall( + /*indirect=*/ 0x01, + /*gasOffset=*/ 0x12345678, + /*addrOffset=*/ 0xa2345678, + /*argsOffset=*/ 0xb2345678, + /*argsSize=*/ 0xc2345678, + /*retOffset=*/ 0xd2345678, + /*retSize=*/ 0xe2345678, + /*successOffset=*/ 0xf2345678, + ), ]; const actual = encodeToBytecode(instructions); diff --git a/yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts similarity index 86% rename from yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.ts rename to yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts index 8b200e5800c..1033cb5f785 100644 --- a/yarn-project/acir-simulator/src/avm/serialization/bytecode_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts @@ -3,7 +3,8 @@ import { Address, And, BlockNumber, - CMov, // Call, + CMov, + Call, CalldataCopy, Cast, ChainId, @@ -35,14 +36,15 @@ import { Sender, Set, Shl, - Shr, // StaticCall, + Shr, + StaticCall, StorageAddress, Sub, Timestamp, Version, Xor, } from '../opcodes/index.js'; -import { Instruction } from '../opcodes/instruction.js'; +import type { Instruction } from '../opcodes/index.js'; import { BufferCursor } from './buffer_cursor.js'; import { Opcode } from './instruction_serialization.js'; @@ -52,8 +54,10 @@ interface DeserializableInstruction { } export type InstructionSet = Map; -const INSTRUCTION_SET: InstructionSet = new Map( - [ +// TODO(4359): This is a function so that Call and StaticCall can be lazily resolved. +// This is a temporary solution until we solve the dependency cycle. +const INSTRUCTION_SET = () => + new Map([ [Add.opcode, Add], [Sub.opcode, Sub], [Mul.opcode, Mul], @@ -116,16 +120,15 @@ const INSTRUCTION_SET: InstructionSet = new Map 100 ? text.slice(0, 100) + '...' : text}"`); } /** @@ -299,14 +309,14 @@ export class ClientExecutionContext extends ViewDataOracle { * @param targetContractAddress - The address of the contract to call. * @param functionSelector - The function selector of the function to call. * @param argsHash - The packed arguments to pass to the function. - * @param sideffectCounter - The side effect counter at the start of the call. + * @param sideEffectCounter - The side effect counter at the start of the call. * @returns The execution result. */ async callPrivateFunction( targetContractAddress: AztecAddress, functionSelector: FunctionSelector, argsHash: Fr, - sideffectCounter: number, + sideEffectCounter: number, ) { this.log( `Calling private function ${this.contractAddress}:${functionSelector} from ${this.callContext.storageContractAddress}`, @@ -327,7 +337,7 @@ export class ClientExecutionContext extends ViewDataOracle { const derivedCallContext = await this.deriveCallContext( targetContractAddress, targetArtifact, - sideffectCounter, + sideEffectCounter, false, false, ); @@ -343,6 +353,7 @@ export class ClientExecutionContext extends ViewDataOracle { this.noteCache, this.db, this.curve, + this.node, ); const childExecutionResult = await executePrivateFunction( diff --git a/yarn-project/acir-simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/db_oracle.ts rename to yarn-project/simulator/src/client/db_oracle.ts diff --git a/yarn-project/acir-simulator/src/client/execution_note_cache.ts b/yarn-project/simulator/src/client/execution_note_cache.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/execution_note_cache.ts rename to yarn-project/simulator/src/client/execution_note_cache.ts diff --git a/yarn-project/acir-simulator/src/client/execution_result.test.ts b/yarn-project/simulator/src/client/execution_result.test.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/execution_result.test.ts rename to yarn-project/simulator/src/client/execution_result.test.ts diff --git a/yarn-project/acir-simulator/src/client/execution_result.ts b/yarn-project/simulator/src/client/execution_result.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/execution_result.ts rename to yarn-project/simulator/src/client/execution_result.ts diff --git a/yarn-project/acir-simulator/src/client/index.ts b/yarn-project/simulator/src/client/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/index.ts rename to yarn-project/simulator/src/client/index.ts diff --git a/yarn-project/acir-simulator/src/client/pick_notes.test.ts b/yarn-project/simulator/src/client/pick_notes.test.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/pick_notes.test.ts rename to yarn-project/simulator/src/client/pick_notes.test.ts diff --git a/yarn-project/acir-simulator/src/client/pick_notes.ts b/yarn-project/simulator/src/client/pick_notes.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/pick_notes.ts rename to yarn-project/simulator/src/client/pick_notes.ts diff --git a/yarn-project/acir-simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts similarity index 93% rename from yarn-project/acir-simulator/src/client/private_execution.test.ts rename to yarn-project/simulator/src/client/private_execution.test.ts index f7a66112551..74fc04355c4 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -1,4 +1,4 @@ -import { L1ToL2Message, Note, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; +import { AztecNode, L1ToL2Message, Note, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, CallContext, @@ -25,7 +25,7 @@ import { computeVarArgsHash, siloCommitment, } from '@aztec/circuits.js/abis'; -import { makeContractDeploymentData } from '@aztec/circuits.js/factories'; +import { makeContractDeploymentData, makeHeader } from '@aztec/circuits.js/factories'; import { FunctionArtifact, FunctionSelector, @@ -41,7 +41,7 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, GrumpkinScalar } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { FieldsOf } from '@aztec/foundation/types'; -import { AztecLmdbStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { AppendOnlyTree, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; import { ChildContractArtifact, @@ -68,6 +68,8 @@ jest.setTimeout(60_000); describe('Private Execution test suite', () => { let oracle: MockProxy; + let node: MockProxy; + let acirSimulator: AcirSimulator; let header = Header.empty(); @@ -138,7 +140,7 @@ describe('Private Execution test suite', () => { throw new Error(`Unknown tree ${name}`); } if (!trees[name]) { - const db = await AztecLmdbStore.openTmp(); + const db = openTmpStore(); const pedersen = new Pedersen(); trees[name] = await newTree(StandardTree, db, pedersen, name, treeHeights[name]); } @@ -220,7 +222,7 @@ describe('Private Execution test suite', () => { }); oracle.getHeader.mockResolvedValue(header); - acirSimulator = new AcirSimulator(oracle); + acirSimulator = new AcirSimulator(oracle, node); }); describe('empty constructor', () => { @@ -314,7 +316,7 @@ describe('Private Execution test suite', () => { expect(result.newNotes).toHaveLength(1); const newNote = result.newNotes[0]; - expect(newNote.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner.toField())); + expect(newNote.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner)); const newCommitments = sideEffectArrayToValueArray( nonEmptySideEffects(result.callStackItem.publicInputs.newCommitments), @@ -334,7 +336,7 @@ describe('Private Execution test suite', () => { expect(result.newNotes).toHaveLength(1); const newNote = result.newNotes[0]; - expect(newNote.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner.toField())); + expect(newNote.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner)); const newCommitments = sideEffectArrayToValueArray( nonEmptySideEffects(result.callStackItem.publicInputs.newCommitments), @@ -351,8 +353,8 @@ describe('Private Execution test suite', () => { const amountToTransfer = 100n; const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create'); - const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField()); - const recipientStorageSlot = computeSlotForMapping(new Fr(1n), recipient.toField()); + const storageSlot = computeSlotForMapping(new Fr(1n), owner); + const recipientStorageSlot = computeSlotForMapping(new Fr(1n), recipient); const notes = [buildNote(60n, owner, storageSlot), buildNote(80n, owner, storageSlot)]; oracle.getNotes.mockResolvedValue(notes); @@ -405,7 +407,7 @@ describe('Private Execution test suite', () => { const balance = 160n; const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create'); - const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField()); + const storageSlot = computeSlotForMapping(new Fr(1n), owner); const notes = [buildNote(balance, owner, storageSlot)]; oracle.getNotes.mockResolvedValue(notes); @@ -903,7 +905,7 @@ describe('Private Execution test suite', () => { expect(result.newNotes).toHaveLength(1); const noteAndSlot = result.newNotes[0]; - expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner.toField())); + expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner)); expect(noteAndSlot.note.items[0]).toEqual(new Fr(amountToTransfer)); @@ -913,7 +915,7 @@ describe('Private Execution test suite', () => { expect(newCommitments).toHaveLength(1); const commitment = newCommitments[0]; - const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField()); + const storageSlot = computeSlotForMapping(new Fr(1n), owner); const innerNoteHash = await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, noteAndSlot.note); expect(commitment).toEqual(innerNoteHash); @@ -984,7 +986,7 @@ describe('Private Execution test suite', () => { expect(execInsert.newNotes).toHaveLength(1); const noteAndSlot = execInsert.newNotes[0]; - expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner.toField())); + expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner)); expect(noteAndSlot.note.items[0]).toEqual(new Fr(amountToTransfer)); @@ -994,7 +996,7 @@ describe('Private Execution test suite', () => { expect(newCommitments).toHaveLength(1); const commitment = newCommitments[0]; - const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField()); + const storageSlot = computeSlotForMapping(new Fr(1n), owner); const innerNoteHash = await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, noteAndSlot.note); expect(commitment).toEqual(innerNoteHash); @@ -1040,7 +1042,7 @@ describe('Private Execution test suite', () => { expect(result.newNotes).toHaveLength(1); const noteAndSlot = result.newNotes[0]; - expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner.toField())); + expect(noteAndSlot.storageSlot).toEqual(computeSlotForMapping(new Fr(1n), owner)); expect(noteAndSlot.note.items[0]).toEqual(new Fr(amountToTransfer)); @@ -1050,7 +1052,7 @@ describe('Private Execution test suite', () => { expect(newCommitments).toHaveLength(1); const commitment = newCommitments[0]; - const storageSlot = computeSlotForMapping(new Fr(1n), owner.toField()); + const storageSlot = computeSlotForMapping(new Fr(1n), owner); expect(commitment).toEqual( await acirSimulator.computeInnerNoteHash(contractAddress, storageSlot, noteAndSlot.note), ); @@ -1127,4 +1129,68 @@ describe('Private Execution test suite', () => { expect(result.returnValues).toEqual(portalContractAddress.toField().value); }); }); + + describe('Private global variables', () => { + let chainId: Fr; + let version: Fr; + let args: any[]; + let artifact: FunctionArtifact; + + beforeAll(() => { + chainId = Fr.random(); + version = Fr.random(); + args = [chainId, version]; + + artifact = getFunctionArtifact(TestContractArtifact, 'assert_private_global_vars'); + oracle.getFunctionArtifact.mockImplementation(() => Promise.resolve(artifact)); + }); + + it('Private global vars are correctly set', () => { + // Chain id and version set in tx context is the same as the ones we pass via args so this should not throw + expect(() => runSimulator({ artifact, msgSender: owner, args, txContext: { chainId, version } })).not.toThrow(); + }); + + it('Throws when chainId is incorrectly set', async () => { + // We set the chainId in the tx context to a different value than the one we pass via args so the simulator should throw + const unexpectedChainId = Fr.random(); + await expect( + runSimulator({ artifact, msgSender: owner, args, txContext: { chainId: unexpectedChainId, version } }), + ).rejects.toThrowError('Invalid chain id'); + }); + + it('Throws when version is incorrectly set', async () => { + // We set the version in the tx context to a different value than the one we pass via args so the simulator should throw + const unexpectedVersion = Fr.random(); + await expect( + runSimulator({ artifact, msgSender: owner, args, txContext: { chainId, version: unexpectedVersion } }), + ).rejects.toThrowError('Invalid version'); + }); + }); + + describe('Historical header in private context', () => { + let artifact: FunctionArtifact; + + beforeAll(() => { + artifact = getFunctionArtifact(TestContractArtifact, 'assert_header_private'); + oracle.getFunctionArtifact.mockImplementation(() => Promise.resolve(artifact)); + + header = makeHeader(); + + oracle.getHeader.mockClear(); + oracle.getHeader.mockResolvedValue(header); + }); + + it('Header is correctly set', () => { + const args = [header.hash()]; + + expect(() => runSimulator({ artifact, msgSender: owner, args })).not.toThrow(); + }); + + it('Throws when header is not as expected', async () => { + const unexpectedHeaderHash = Fr.random(); + const args = [unexpectedHeaderHash]; + + await expect(runSimulator({ artifact, msgSender: owner, args })).rejects.toThrowError('Invalid header hash'); + }); + }); }); diff --git a/yarn-project/acir-simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts similarity index 98% rename from yarn-project/acir-simulator/src/client/private_execution.ts rename to yarn-project/simulator/src/client/private_execution.ts index f02ca372be9..cf2e579af08 100644 --- a/yarn-project/acir-simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -53,7 +53,7 @@ export async function executePrivateFunction( publicInputs.unencryptedLogsHash = to2Fields(unencryptedLogs.hash()); publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength()); - const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs, false); + const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs); const returnValues = decodeReturnValues(artifact, publicInputs.returnValues); const readRequestPartialWitnesses = context.getReadRequestPartialWitnesses(publicInputs.readRequests); const newNotes = context.getNewNotes(); diff --git a/yarn-project/acir-simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts similarity index 96% rename from yarn-project/acir-simulator/src/client/simulator.test.ts rename to yarn-project/simulator/src/client/simulator.test.ts index 7c5a3e830e2..ed7b3df1369 100644 --- a/yarn-project/acir-simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -1,4 +1,4 @@ -import { Note } from '@aztec/circuit-types'; +import { AztecNode, Note } from '@aztec/circuit-types'; import { CompleteAddress } from '@aztec/circuits.js'; import { computeUniqueCommitment, siloCommitment } from '@aztec/circuits.js/abis'; import { ABIParameterVisibility, FunctionArtifactWithDebugMetadata, getFunctionArtifact } from '@aztec/foundation/abi'; @@ -14,6 +14,8 @@ import { AcirSimulator } from './simulator.js'; describe('Simulator', () => { let oracle: MockProxy; + let node: MockProxy; + let simulator: AcirSimulator; const ownerPk = GrumpkinScalar.fromString('2dcc5485a58316776299be08c78fa3788a1a7961ae30dc747fb1be17692a8d32'); const ownerCompleteAddress = CompleteAddress.fromPrivateKeyAndPartialAddress(ownerPk, Fr.random()); @@ -25,13 +27,14 @@ describe('Simulator', () => { beforeEach(() => { oracle = mock(); + node = mock(); oracle.getNullifierKeyPair.mockResolvedValue({ secretKey: ownerNullifierSecretKey, publicKey: ownerNullifierPublicKey, }); oracle.getCompleteAddress.mockResolvedValue(ownerCompleteAddress); - simulator = new AcirSimulator(oracle); + simulator = new AcirSimulator(oracle, node); }); describe('computeNoteHashAndNullifier', () => { diff --git a/yarn-project/acir-simulator/src/client/simulator.ts b/yarn-project/simulator/src/client/simulator.ts similarity index 98% rename from yarn-project/acir-simulator/src/client/simulator.ts rename to yarn-project/simulator/src/client/simulator.ts index 514bf8b04ca..be2852dce69 100644 --- a/yarn-project/acir-simulator/src/client/simulator.ts +++ b/yarn-project/simulator/src/client/simulator.ts @@ -32,7 +32,7 @@ export class AcirSimulator { private static solver: Promise; // ACVM's backend private log: DebugLogger; - constructor(private db: DBOracle) { + constructor(private db: DBOracle, private node: AztecNode) { this.log = createDebugLogger('aztec:simulator'); } @@ -107,6 +107,7 @@ export class AcirSimulator { new ExecutionNoteCache(), this.db, curve, + this.node, ); try { @@ -133,13 +134,12 @@ export class AcirSimulator { request: FunctionCall, entryPointArtifact: FunctionArtifactWithDebugMetadata, contractAddress: AztecAddress, - aztecNode?: AztecNode, ) { if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) { throw new Error(`Cannot run ${entryPointArtifact.functionType} function as constrained`); } - const context = new ViewDataOracle(contractAddress, [], this.db, aztecNode); + const context = new ViewDataOracle(contractAddress, [], this.db, this.node); try { return await executeUnconstrainedFunction( diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts b/yarn-project/simulator/src/client/unconstrained_execution.test.ts similarity index 93% rename from yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts rename to yarn-project/simulator/src/client/unconstrained_execution.test.ts index c8c114b756c..68b7ba6764c 100644 --- a/yarn-project/acir-simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.test.ts @@ -1,4 +1,4 @@ -import { FunctionCall, Note } from '@aztec/circuit-types'; +import { AztecNode, FunctionCall, Note } from '@aztec/circuit-types'; import { CompleteAddress, FunctionData, Header } from '@aztec/circuits.js'; import { FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -12,11 +12,12 @@ import { AcirSimulator } from './simulator.js'; describe('Unconstrained Execution test suite', () => { let oracle: ReturnType>; + let node: ReturnType>; let acirSimulator: AcirSimulator; beforeEach(() => { oracle = mock(); - acirSimulator = new AcirSimulator(oracle); + acirSimulator = new AcirSimulator(oracle, node); }); describe('private token contract', () => { diff --git a/yarn-project/acir-simulator/src/client/unconstrained_execution.ts b/yarn-project/simulator/src/client/unconstrained_execution.ts similarity index 100% rename from yarn-project/acir-simulator/src/client/unconstrained_execution.ts rename to yarn-project/simulator/src/client/unconstrained_execution.ts diff --git a/yarn-project/acir-simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts similarity index 98% rename from yarn-project/acir-simulator/src/client/view_data_oracle.ts rename to yarn-project/simulator/src/client/view_data_oracle.ts index 14cc8ea4bfd..5edf08a504f 100644 --- a/yarn-project/acir-simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -27,7 +27,7 @@ export class ViewDataOracle extends TypedOracle { /** List of transient auth witnesses to be used during this simulation */ protected readonly authWitnesses: AuthWitness[], protected readonly db: DBOracle, - protected readonly aztecNode: AztecNode | undefined, + protected readonly aztecNode: AztecNode, protected log = createDebugLogger('aztec:simulator:client_view_context'), ) { super(); @@ -230,10 +230,6 @@ export class ViewDataOracle extends TypedOracle { * @param numberOfElements - Number of elements to read from the starting storage slot. */ public async storageRead(startStorageSlot: Fr, numberOfElements: number) { - if (!this.aztecNode) { - throw new Error('Aztec node is undefined, cannot read storage.'); - } - const values = []; for (let i = 0n; i < numberOfElements; i++) { const storageSlot = new Fr(startStorageSlot.value + i); diff --git a/yarn-project/acir-simulator/src/common/errors.ts b/yarn-project/simulator/src/common/errors.ts similarity index 100% rename from yarn-project/acir-simulator/src/common/errors.ts rename to yarn-project/simulator/src/common/errors.ts diff --git a/yarn-project/acir-simulator/src/common/index.ts b/yarn-project/simulator/src/common/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/common/index.ts rename to yarn-project/simulator/src/common/index.ts diff --git a/yarn-project/acir-simulator/src/common/packed_args_cache.ts b/yarn-project/simulator/src/common/packed_args_cache.ts similarity index 100% rename from yarn-project/acir-simulator/src/common/packed_args_cache.ts rename to yarn-project/simulator/src/common/packed_args_cache.ts diff --git a/yarn-project/acir-simulator/src/common/side_effect_counter.ts b/yarn-project/simulator/src/common/side_effect_counter.ts similarity index 100% rename from yarn-project/acir-simulator/src/common/side_effect_counter.ts rename to yarn-project/simulator/src/common/side_effect_counter.ts diff --git a/yarn-project/acir-simulator/src/index.ts b/yarn-project/simulator/src/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/index.ts rename to yarn-project/simulator/src/index.ts diff --git a/yarn-project/acir-simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/db.ts rename to yarn-project/simulator/src/public/db.ts diff --git a/yarn-project/acir-simulator/src/public/execution.ts b/yarn-project/simulator/src/public/execution.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/execution.ts rename to yarn-project/simulator/src/public/execution.ts diff --git a/yarn-project/acir-simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/executor.ts rename to yarn-project/simulator/src/public/executor.ts diff --git a/yarn-project/acir-simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts similarity index 77% rename from yarn-project/acir-simulator/src/public/index.test.ts rename to yarn-project/simulator/src/public/index.test.ts index e96cd2ecaa9..3b84353386e 100644 --- a/yarn-project/acir-simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -7,6 +7,7 @@ import { Header, L1_TO_L2_MSG_TREE_HEIGHT, } from '@aztec/circuits.js'; +import { makeHeader } from '@aztec/circuits.js/factories'; import { FunctionArtifact, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; @@ -42,7 +43,9 @@ describe('ACIR public execution simulator', () => { publicContracts = mock(); commitmentsDb = mock(); - header = Header.empty(); + const randomInt = Math.floor(Math.random() * 1000000); + header = makeHeader(randomInt); + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); }, 10000); @@ -88,7 +91,7 @@ describe('ACIR public execution simulator', () => { const execution: PublicExecution = { contractAddress, functionData, args, callContext }; const result = await executor.simulate(execution, GlobalVariables.empty()); - const recipientBalanceStorageSlot = computeSlotForMapping(new Fr(6n), recipient.toField()); + const recipientBalanceStorageSlot = computeSlotForMapping(new Fr(6n), recipient); const totalSupplyStorageSlot = new Fr(4n); const expectedBalance = new Fr(previousBalance.value + mintAmount); @@ -110,7 +113,7 @@ describe('ACIR public execution simulator', () => { ]); const mintersStorageSlot = new Fr(2n); - const isMinterStorageSlot = computeSlotForMapping(mintersStorageSlot, msgSender.toField()); + const isMinterStorageSlot = computeSlotForMapping(mintersStorageSlot, msgSender); // Note: There is only 1 storage read (for the isMinter value) because the other 2 reads get overwritten by // the updates expect(result.contractStorageReads).toEqual([ @@ -152,8 +155,8 @@ describe('ACIR public execution simulator', () => { startSideEffectCounter: 0, }); - recipientStorageSlot = computeSlotForMapping(new Fr(6n), recipient.toField()); - senderStorageSlot = computeSlotForMapping(new Fr(6n), Fr.fromBuffer(sender.toBuffer())); + recipientStorageSlot = computeSlotForMapping(new Fr(6n), recipient); + senderStorageSlot = computeSlotForMapping(new Fr(6n), sender); publicContracts.getBytecode.mockResolvedValue(Buffer.from(transferArtifact.bytecode, 'base64')); @@ -231,11 +234,7 @@ describe('ACIR public execution simulator', () => { const initialValue = 3n; const functionData = new FunctionData(parentEntryPointFnSelector, isInternal ?? false, false, false); - const args = encodeArguments(parentEntryPointFn, [ - childContractAddress.toField(), - childValueFnSelector.toField(), - initialValue, - ]); + const args = encodeArguments(parentEntryPointFn, [childContractAddress, childValueFnSelector, initialValue]); const callContext = CallContext.from({ msgSender: AztecAddress.random(), @@ -264,7 +263,14 @@ describe('ACIR public execution simulator', () => { }); const execution: PublicExecution = { contractAddress: parentContractAddress, functionData, args, callContext }; - const globalVariables = new GlobalVariables(new Fr(69), new Fr(420), new Fr(1), new Fr(7)); + const globalVariables = new GlobalVariables( + new Fr(69), + new Fr(420), + new Fr(1), + new Fr(7), + EthAddress.fromField(new Fr(8)), + AztecAddress.fromField(new Fr(9)), + ); if (isInternal === undefined) { await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError(/Method not found -/); @@ -304,7 +310,7 @@ describe('ACIR public execution simulator', () => { const msgSender = AztecAddress.random(); const secretHash = Fr.random(); - const args = encodeArguments(shieldArtifact, [msgSender.toField(), amount, secretHash, Fr.ZERO]); + const args = encodeArguments(shieldArtifact, [msgSender, amount, secretHash, Fr.ZERO]); const callContext = CallContext.from({ msgSender: msgSender, @@ -429,9 +435,9 @@ describe('ACIR public execution simulator', () => { const computeArgs = () => encodeArguments(mintPublicArtifact, [ - tokenRecipient.toField(), + tokenRecipient, bridgedAmount, - canceller.toField(), + canceller, messageKey ?? preimage.hash(), secret, ]); @@ -449,7 +455,14 @@ describe('ACIR public execution simulator', () => { }); const computeGlobalVariables = () => - new GlobalVariables(new Fr(preimage.sender.chainId), new Fr(preimage.recipient.version), Fr.ZERO, Fr.ZERO); + new GlobalVariables( + new Fr(preimage.sender.chainId), + new Fr(preimage.recipient.version), + Fr.ZERO, + Fr.ZERO, + EthAddress.ZERO, + AztecAddress.ZERO, + ); const mockOracles = () => { publicContracts.getBytecode.mockResolvedValue(Buffer.from(mintPublicArtifact.bytecode, 'base64')); @@ -618,4 +631,140 @@ describe('ACIR public execution simulator', () => { }); }); }); + + describe('Global variables in public context', () => { + let contractAddress: AztecAddress; + let callContext: CallContext; + let assertGlobalVarsArtifact: FunctionArtifact; + let functionData: FunctionData; + + const modifyGlobalVariables = (globalVariables: GlobalVariables, propertyIndex: number, value: any) => { + const globalVariablesFields = GlobalVariables.getFields(globalVariables) as unknown as any[]; + globalVariablesFields[propertyIndex] = value; + return GlobalVariables.fromFields(globalVariablesFields); + }; + + beforeAll(() => { + contractAddress = AztecAddress.random(); + callContext = CallContext.from({ + msgSender: AztecAddress.random(), + storageContractAddress: AztecAddress.random(), + portalContractAddress: EthAddress.ZERO, + functionSelector: FunctionSelector.empty(), + isContractDeployment: false, + isDelegateCall: false, + isStaticCall: false, + startSideEffectCounter: 0, + }); + assertGlobalVarsArtifact = TestContractArtifact.functions.find(f => f.name === 'assert_public_global_vars')!; + functionData = FunctionData.fromAbi(assertGlobalVarsArtifact); + }); + + beforeEach(() => { + publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertGlobalVarsArtifact.bytecode, 'base64')); + }); + + // Note: Order here has to match the order of the properties in GlobalVariables.getFields(...) function. + const testCases = [ + { value: new Fr(1), invalidValue: Fr.random(), description: 'Chain ID' }, + { value: new Fr(1), invalidValue: Fr.random(), description: 'Version' }, + { value: new Fr(1), invalidValue: Fr.random(), description: 'Block number' }, + { value: new Fr(1), invalidValue: Fr.random(), description: 'Timestamp' }, + { value: EthAddress.random(), invalidValue: EthAddress.random(), description: 'Coinbase' }, + { + value: AztecAddress.random(), + invalidValue: AztecAddress.random(), + description: 'Fee recipient', + }, + ]; + + testCases.forEach(({ value, invalidValue, description }, i: number) => { + describe(`${description}`, () => { + let globalVariables: GlobalVariables; + + beforeAll(() => { + // We create a new global variables object containing non-zero value in place of the tested property + globalVariables = modifyGlobalVariables(GlobalVariables.empty(), i, value); + }); + + it('Valid', () => { + let args: Fr[]; + { + // We create the args by just serializing the reference global variables object + const rawArgs = GlobalVariables.getFields(globalVariables) as unknown as any[]; + args = encodeArguments(assertGlobalVarsArtifact, rawArgs); + } + + const execution: PublicExecution = { contractAddress, functionData, args, callContext }; + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); + + expect(() => executor.simulate(execution, globalVariables)).not.toThrow(); + }); + + it('Invalid', async () => { + let args: Fr[]; + { + // We create the args by modifying the global variables object to contain an invalid value in place of + // the tested property + const modifiedGlobalVariables = modifyGlobalVariables(globalVariables, i, invalidValue); + const rawArgs = GlobalVariables.getFields(modifiedGlobalVariables) as unknown as any[]; + args = encodeArguments(assertGlobalVarsArtifact, rawArgs); + } + + const execution: PublicExecution = { contractAddress, functionData, args, callContext }; + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); + + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError( + `Invalid ${description.toLowerCase()}`, + ); + }); + }); + }); + }); + + describe('Historical header in public context', () => { + let contractAddress: AztecAddress; + let callContext: CallContext; + let assertHeaderPublicArtifact: FunctionArtifact; + let functionData: FunctionData; + + beforeAll(() => { + contractAddress = AztecAddress.random(); + callContext = CallContext.from({ + msgSender: AztecAddress.random(), + storageContractAddress: AztecAddress.random(), + portalContractAddress: EthAddress.ZERO, + functionSelector: FunctionSelector.empty(), + isContractDeployment: false, + isDelegateCall: false, + isStaticCall: false, + startSideEffectCounter: 0, + }); + assertHeaderPublicArtifact = TestContractArtifact.functions.find(f => f.name === 'assert_header_public')!; + functionData = FunctionData.fromAbi(assertHeaderPublicArtifact); + }); + + beforeEach(() => { + publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertHeaderPublicArtifact.bytecode, 'base64')); + }); + + it('Header is correctly set', () => { + const args = encodeArguments(assertHeaderPublicArtifact, [header.hash()]); + + const execution: PublicExecution = { contractAddress, functionData, args, callContext }; + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); + + expect(() => executor.simulate(execution, GlobalVariables.empty())).not.toThrow(); + }); + + it('Throws when header is not as expected', async () => { + const unexpectedHeaderHash = Fr.random(); + const args = encodeArguments(assertHeaderPublicArtifact, [unexpectedHeaderHash]); + + const execution: PublicExecution = { contractAddress, functionData, args, callContext }; + executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); + + await expect(executor.simulate(execution, GlobalVariables.empty())).rejects.toThrowError('Invalid header hash'); + }); + }); }); diff --git a/yarn-project/acir-simulator/src/public/index.ts b/yarn-project/simulator/src/public/index.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/index.ts rename to yarn-project/simulator/src/public/index.ts diff --git a/yarn-project/acir-simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/public_execution_context.ts rename to yarn-project/simulator/src/public/public_execution_context.ts diff --git a/yarn-project/acir-simulator/src/public/state_actions.ts b/yarn-project/simulator/src/public/state_actions.ts similarity index 100% rename from yarn-project/acir-simulator/src/public/state_actions.ts rename to yarn-project/simulator/src/public/state_actions.ts diff --git a/yarn-project/acir-simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts similarity index 100% rename from yarn-project/acir-simulator/src/test/utils.ts rename to yarn-project/simulator/src/test/utils.ts diff --git a/yarn-project/simulator/src/utils.ts b/yarn-project/simulator/src/utils.ts new file mode 100644 index 00000000000..a47e4e390ba --- /dev/null +++ b/yarn-project/simulator/src/utils.ts @@ -0,0 +1,18 @@ +import { pedersenHash } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; + +/** + * Computes the resulting storage slot for an entry in a mapping. + * @param mappingSlot - The slot of the mapping within state. + * @param key - The key of the mapping. + * @returns The slot in the contract storage where the value is stored. + */ +export function computeSlotForMapping( + mappingSlot: Fr, + key: { + /** Serialize to a field. */ + toField: () => Fr; + }, +) { + return Fr.fromBuffer(pedersenHash([mappingSlot, key.toField()].map(field => field.toBuffer()))); +} diff --git a/yarn-project/acir-simulator/tsconfig.json b/yarn-project/simulator/tsconfig.json similarity index 100% rename from yarn-project/acir-simulator/tsconfig.json rename to yarn-project/simulator/tsconfig.json diff --git a/yarn-project/tsconfig.json b/yarn-project/tsconfig.json index 7100672a7f2..3f7c45f343c 100644 --- a/yarn-project/tsconfig.json +++ b/yarn-project/tsconfig.json @@ -19,7 +19,7 @@ }, "references": [ { "path": "accounts/tsconfig.json" }, - { "path": "acir-simulator/tsconfig.json" }, + { "path": "simulator/tsconfig.json" }, { "path": "archiver/tsconfig.json" }, { "path": "aztec-faucet/tsconfig.json" }, { "path": "aztec.js/tsconfig.json" }, @@ -39,6 +39,7 @@ { "path": "noir-protocol-circuits/tsconfig.json" }, { "path": "p2p/tsconfig.json" }, { "path": "p2p-bootstrap/tsconfig.json" }, + { "path": "protocol-contracts/tsconfig.json" }, { "path": "prover-client/tsconfig.json" }, { "path": "sequencer-client/tsconfig.json" }, { "path": "types/tsconfig.json" }, diff --git a/yarn-project/typedoc.json b/yarn-project/typedoc.json index f2e4de84a01..a5dee75ec5f 100644 --- a/yarn-project/typedoc.json +++ b/yarn-project/typedoc.json @@ -3,7 +3,7 @@ "entryPointStrategy": "packages", "entryPoints": [ "accounts", - "acir-simulator", + "simulator", "archiver", "aztec-cli", "pxe", diff --git a/yarn-project/types/src/contracts/contract_class.test.ts b/yarn-project/types/src/contracts/contract_class.test.ts deleted file mode 100644 index 8521217473c..00000000000 --- a/yarn-project/types/src/contracts/contract_class.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SerializableContractClass } from './contract_class.js'; - -describe('ContractClass', () => { - it('can serialize and deserialize a contract class', () => { - const contractClass = SerializableContractClass.random(); - expect(SerializableContractClass.fromBuffer(contractClass.toBuffer())).toEqual(contractClass); - }); -}); diff --git a/yarn-project/types/src/contracts/contract_class.ts b/yarn-project/types/src/contracts/contract_class.ts index b8444e166df..c575485ad33 100644 --- a/yarn-project/types/src/contracts/contract_class.ts +++ b/yarn-project/types/src/contracts/contract_class.ts @@ -1,10 +1,14 @@ import { FunctionSelector } from '@aztec/foundation/abi'; -import { randomBytes } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize'; +import { PartialBy } from '@aztec/foundation/types'; const VERSION = 1 as const; +/** + * A Contract Class in the protocol. Aztec differentiates contracts classes and instances, where a + * contract class represents the code of the contract, but holds no state. Classes are identified by + * an id that is a commitment to all its data. + */ export interface ContractClass { /** Version of the contract class. */ version: typeof VERSION; @@ -18,66 +22,7 @@ export interface ContractClass { packedBytecode: Buffer; } -/** Serializable implementation of the contract class interface. */ -export class SerializableContractClass implements ContractClass { - /** Version identifier. Initially one, bumped for any changes to the contract class struct. */ - public readonly version = VERSION; - - public readonly artifactHash: Fr; - public readonly packedBytecode: Buffer; - public readonly privateFunctions: SerializablePrivateFunction[]; - public readonly publicFunctions: SerializablePublicFunction[]; - - constructor(contractClass: ContractClass) { - if (contractClass.version !== VERSION) { - throw new Error(`Unexpected contract class version ${contractClass.version}`); - } - this.privateFunctions = contractClass.privateFunctions.map(x => new SerializablePrivateFunction(x)); - this.publicFunctions = contractClass.publicFunctions.map(x => new SerializablePublicFunction(x)); - this.artifactHash = contractClass.artifactHash; - this.packedBytecode = contractClass.packedBytecode; - } - - /** Returns a copy of this object with its id included. */ - withId(id: Fr): ContractClassWithId { - return { ...this, id }; - } - - public toBuffer() { - return serializeToBuffer( - numToUInt8(this.version), - this.artifactHash, - this.privateFunctions.length, - this.privateFunctions, - this.publicFunctions.length, - this.publicFunctions, - this.packedBytecode.length, - this.packedBytecode, - ); - } - - static fromBuffer(bufferOrReader: BufferReader | Buffer) { - const reader = BufferReader.asReader(bufferOrReader); - return new SerializableContractClass({ - version: reader.readUInt8() as typeof VERSION, - artifactHash: reader.readObject(Fr), - privateFunctions: reader.readVector(SerializablePrivateFunction), - publicFunctions: reader.readVector(SerializablePublicFunction), - packedBytecode: reader.readBuffer(), - }); - } - - static random() { - return new SerializableContractClass({ - version: VERSION, - artifactHash: Fr.random(), - privateFunctions: [SerializablePrivateFunction.random()], - publicFunctions: [SerializablePublicFunction.random()], - packedBytecode: randomBytes(32), - }); - } -} - +/** Private function definition within a contract class. */ export interface PrivateFunction { /** Selector of the function. Calculated as the hash of the method name and parameters. The specification of this is not enforced by the protocol. */ selector: FunctionSelector; @@ -90,40 +35,7 @@ export interface PrivateFunction { isInternal: boolean; } -/** Private function in a Contract Class. */ -export class SerializablePrivateFunction { - public readonly selector: FunctionSelector; - public readonly vkHash: Fr; - public readonly isInternal: boolean; - - constructor(privateFunction: PrivateFunction) { - this.selector = privateFunction.selector; - this.vkHash = privateFunction.vkHash; - this.isInternal = privateFunction.isInternal; - } - - public toBuffer() { - return serializeToBuffer(this.selector, this.vkHash, this.isInternal); - } - - static fromBuffer(bufferOrReader: BufferReader | Buffer): PrivateFunction { - const reader = BufferReader.asReader(bufferOrReader); - return new SerializablePrivateFunction({ - selector: reader.readObject(FunctionSelector), - vkHash: reader.readObject(Fr), - isInternal: reader.readBoolean(), - }); - } - - static random() { - return new SerializablePrivateFunction({ - selector: FunctionSelector.random(), - vkHash: Fr.random(), - isInternal: false, - }); - } -} - +/** Public function definition within a contract class. */ export interface PublicFunction { /** Selector of the function. Calculated as the hash of the method name and parameters. The specification of this is not enforced by the protocol. */ selector: FunctionSelector; @@ -136,40 +48,19 @@ export interface PublicFunction { isInternal: boolean; } -/** - * Public function in a Contract Class. Use `packedBytecode` in the parent class once supported. - */ -export class SerializablePublicFunction { - public readonly selector: FunctionSelector; - public readonly bytecode: Buffer; - public readonly isInternal: boolean; - - constructor(publicFunction: PublicFunction) { - this.selector = publicFunction.selector; - this.bytecode = publicFunction.bytecode; - this.isInternal = publicFunction.isInternal; - } - - public toBuffer() { - return serializeToBuffer(this.selector, this.bytecode.length, this.bytecode, this.isInternal); - } - - static fromBuffer(bufferOrReader: BufferReader | Buffer): PublicFunction { - const reader = BufferReader.asReader(bufferOrReader); - return new SerializablePublicFunction({ - selector: reader.readObject(FunctionSelector), - bytecode: reader.readBuffer(), - isInternal: reader.readBoolean(), - }); - } - - static random() { - return new SerializablePublicFunction({ - selector: FunctionSelector.random(), - bytecode: randomBytes(32), - isInternal: false, - }); - } +/** Commitments to fields of a contract class. */ +interface ContractClassCommitments { + /** Identifier of the contract class. */ + id: Fr; + /** Commitment to the public bytecode. */ + publicBytecodeCommitment: Fr; + /** Root of the private functions tree */ + privateFunctionsRoot: Fr; } -export type ContractClassWithId = ContractClass & { id: Fr }; +/** A contract class with its precomputed id. */ +export type ContractClassWithId = ContractClass & Pick; + +/** A contract class with public bytecode information only. */ +export type ContractClassPublic = PartialBy & + Pick; diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts index 684e46a84a6..1a3f8730a7c 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.test.ts @@ -2,7 +2,8 @@ import { L2Block, L2BlockSource, MerkleTreeId, SiblingPath } from '@aztec/circui import { Fr } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { sleep } from '@aztec/foundation/sleep'; -import { AztecKVStore, AztecLmdbStore } from '@aztec/kv-store'; +import { AztecKVStore } from '@aztec/kv-store'; +import { openTmpStore } from '@aztec/kv-store/utils'; import { INITIAL_LEAF, Pedersen } from '@aztec/merkle-tree'; import { jest } from '@jest/globals'; @@ -103,8 +104,8 @@ describe('server_world_state_synchronizer', () => { ); }; - beforeEach(async () => { - db = await AztecLmdbStore.openTmp(); + beforeEach(() => { + db = openTmpStore(); }); it('can be constructed', () => { diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 472b7df6b99..5d903bf814d 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -87,34 +87,6 @@ __metadata: languageName: unknown linkType: soft -"@aztec/acir-simulator@workspace:^, @aztec/acir-simulator@workspace:acir-simulator": - version: 0.0.0-use.local - resolution: "@aztec/acir-simulator@workspace:acir-simulator" - dependencies: - "@aztec/circuit-types": "workspace:^" - "@aztec/circuits.js": "workspace:^" - "@aztec/foundation": "workspace:^" - "@aztec/kv-store": "workspace:^" - "@aztec/merkle-tree": "workspace:^" - "@aztec/noir-contracts": "workspace:^" - "@jest/globals": ^29.5.0 - "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" - "@types/jest": ^29.5.0 - "@types/levelup": ^5.1.3 - "@types/memdown": ^3.0.2 - "@types/node": ^18.7.23 - jest: ^29.5.0 - jest-mock-extended: ^3.0.4 - levelup: ^5.1.1 - memdown: ^6.1.1 - ts-jest: ^29.1.0 - ts-node: ^10.9.1 - tslib: ^2.4.0 - typescript: ^5.0.4 - viem: ^1.2.5 - languageName: unknown - linkType: soft - "@aztec/archiver@workspace:^, @aztec/archiver@workspace:archiver": version: 0.0.0-use.local resolution: "@aztec/archiver@workspace:archiver" @@ -125,6 +97,7 @@ __metadata: "@aztec/foundation": "workspace:^" "@aztec/kv-store": "workspace:^" "@aztec/l1-artifacts": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/debug": ^4.1.7 @@ -209,6 +182,7 @@ __metadata: "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 @@ -496,6 +470,7 @@ __metadata: "@types/koa__cors": ^4.0.0 "@types/leveldown": ^4.0.3 "@types/levelup": ^5.1.2 + "@types/lodash.chunk": ^4.2.9 "@types/lodash.clonedeepwith": ^4.5.7 "@types/memdown": ^3.0.1 "@types/node": ^18.7.23 @@ -521,6 +496,7 @@ __metadata: koa-router: ^12.0.0 leveldown: ^6.1.1 levelup: ^5.1.1 + lodash.chunk: ^4.2.0 lodash.clonedeepwith: ^4.5.0 memdown: ^6.1.1 pako: ^2.1.0 @@ -733,6 +709,28 @@ __metadata: languageName: unknown linkType: soft +"@aztec/protocol-contracts@workspace:^, @aztec/protocol-contracts@workspace:protocol-contracts": + version: 0.0.0-use.local + resolution: "@aztec/protocol-contracts@workspace:protocol-contracts" + dependencies: + "@aztec/circuits.js": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/types": "workspace:^" + "@jest/globals": ^29.5.0 + "@types/jest": ^29.5.0 + "@types/lodash.omit": ^4.5.9 + "@types/node": ^18.7.23 + jest: ^29.5.0 + jest-mock-extended: ^3.0.3 + lodash.omit: ^4.5.0 + ts-jest: ^29.1.0 + ts-loader: ^9.4.4 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^5.0.4 + languageName: unknown + linkType: soft + "@aztec/prover-client@workspace:prover-client": version: 0.0.0-use.local resolution: "@aztec/prover-client@workspace:prover-client" @@ -753,7 +751,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/pxe@workspace:pxe" dependencies: - "@aztec/acir-simulator": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" @@ -763,6 +760,8 @@ __metadata: "@aztec/noir-compiler": "workspace:^" "@aztec/noir-contracts": "workspace:^" "@aztec/noir-protocol-circuits": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" + "@aztec/simulator": "workspace:^" "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 @@ -812,7 +811,6 @@ __metadata: version: 0.0.0-use.local resolution: "@aztec/sequencer-client@workspace:sequencer-client" dependencies: - "@aztec/acir-simulator": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/ethereum": "workspace:^" @@ -822,6 +820,7 @@ __metadata: "@aztec/merkle-tree": "workspace:^" "@aztec/noir-protocol-circuits": "workspace:^" "@aztec/p2p": "workspace:^" + "@aztec/simulator": "workspace:^" "@aztec/types": "workspace:^" "@aztec/world-state": "workspace:^" "@jest/globals": ^29.5.0 @@ -848,6 +847,36 @@ __metadata: languageName: unknown linkType: soft +"@aztec/simulator@workspace:^, @aztec/simulator@workspace:simulator": + version: 0.0.0-use.local + resolution: "@aztec/simulator@workspace:simulator" + dependencies: + "@aztec/circuit-types": "workspace:^" + "@aztec/circuits.js": "workspace:^" + "@aztec/foundation": "workspace:^" + "@aztec/kv-store": "workspace:^" + "@aztec/merkle-tree": "workspace:^" + "@aztec/noir-contracts": "workspace:^" + "@jest/globals": ^29.5.0 + "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" + "@types/jest": ^29.5.0 + "@types/levelup": ^5.1.3 + "@types/lodash.merge": ^4.6.9 + "@types/memdown": ^3.0.2 + "@types/node": ^18.7.23 + jest: ^29.5.0 + jest-mock-extended: ^3.0.4 + levelup: ^5.1.1 + lodash.merge: ^4.6.2 + memdown: ^6.1.1 + ts-jest: ^29.1.0 + ts-node: ^10.9.1 + tslib: ^2.4.0 + typescript: ^5.0.4 + viem: ^1.2.5 + languageName: unknown + linkType: soft + "@aztec/types@workspace:^, @aztec/types@workspace:types": version: 0.0.0-use.local resolution: "@aztec/types@workspace:types" @@ -3387,7 +3416,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash.chunk@npm:^4.2.7": +"@types/lodash.chunk@npm:^4.2.7, @types/lodash.chunk@npm:^4.2.9": version: 4.2.9 resolution: "@types/lodash.chunk@npm:4.2.9" dependencies: @@ -3432,7 +3461,16 @@ __metadata: languageName: node linkType: hard -"@types/lodash.omit@npm:^4.5.7": +"@types/lodash.merge@npm:^4.6.9": + version: 4.6.9 + resolution: "@types/lodash.merge@npm:4.6.9" + dependencies: + "@types/lodash": "*" + checksum: d0dd6654547c9d8d905184d14aa5c2a37a1ed1c3204f5ab20b7d591a05f34859ef09d3b72c065e94ca1989abf9109eb8230f67c4d64a5768b1d65b9ed8baf8e7 + languageName: node + linkType: hard + +"@types/lodash.omit@npm:^4.5.7, @types/lodash.omit@npm:^4.5.9": version: 4.5.9 resolution: "@types/lodash.omit@npm:4.5.9" dependencies: diff --git a/yellow-paper/docs/addresses-and-keys/address.md b/yellow-paper/docs/addresses-and-keys/address.md new file mode 100644 index 00000000000..1304efcf15b --- /dev/null +++ b/yellow-paper/docs/addresses-and-keys/address.md @@ -0,0 +1,49 @@ +--- +title: Address +--- + +An address is computed as the hash of the following fields: + + +| Field | Type | Description | +|----------|----------|----------| +| `salt` | `Field` | User-generated pseudorandom value for uniqueness. | +| `deployer` | `AztecAddress` | Optional address of the deployer of the contract. | +| `contract_class_id` | `Field` | Identifier of the contract class for this instance. | +| `initialization_hash` | `Field` | Hash of the selector and arguments to the constructor. | +| `portal_contract_address` | `EthereumAddress` | Address of the L1 portal contract, zero if none. | +| `public_keys_hash` | `Field` | Hash of the struct of public keys used for encryption and nullifying by this contract, zero if no public keys. | + +Storing these fields in the address preimage allows any part of the protocol to check them by recomputing the hash and verifying that the address matches. Examples of these checks are: + +- Sending an encrypted note to an undeployed account, which requires the sender app to check the recipient's public key given their address. This scenario also requires the recipient to share with the sender their public key and rest of preimage. +- Having the kernel circuit verify that the code executed at a given address matches the one from the class. +- Asserting that the initialization hash matches the function call in the contract constructor. +- Checking the portal contract address when sending a cross-chain message. + +:::warning +We may remove the `portal_contract_address` as a first-class citizen. +::: + +The hashing scheme for the address should then ensure that checks that are more frequent can be done cheaply, and that data shared out of band is kept manageable. We define the hash to be computed as follows: + +``` +salted_initialization_hash = pedersen([salt, initialization_hash, deployer as Field, portal_contract_address as Field], GENERATOR__SALTED_INITIALIZATION_HASH) +partial_address = pedersen([contract_class_id, salted_initialization_hash], GENERATOR__CONTRACT_PARTIAL_ADDRESS_V1) +address = pedersen([public_keys_hash, partial_address], GENERATOR__CONTRACT_ADDRESS_V1) +``` + +The `public_keys` array can vary depending on the format of keys used by the address, but it is suggested it includes the master keys defined in the [keys section](./keys.md). + +``` +public_keys_hash = pedersen([ + nullifier_pubkey.x, nullifier_pubkey.y, + tagging_pubkey.x, tagging_pubkey.y, + incoming_view_pubkey.x, incoming_view_pubkey.y, + outgoing_view_pubkey.x, outgoing_view_pubkey.y +], GENERATOR__PUBLIC_KEYS) +``` + +This recommended hash format is compatible with the [encryption precompiles](./precompiles.md#encryption-and-tagging-precompiles) initially defined in the protocol and advertised in the canonical [registry](../private-message-delivery/registry.md) for private message delivery. An address that chooses to use a different format for its keys will not be compatible with apps that rely on the registry for note encryption. Nevertheless, new precompiles introduced in future versions of the protocol could use different public keys formats. + + diff --git a/yellow-paper/docs/addresses-and-keys/diversified-and-stealth.md b/yellow-paper/docs/addresses-and-keys/diversified-and-stealth.md index 3da4713d275..51a274e12b4 100644 --- a/yellow-paper/docs/addresses-and-keys/diversified-and-stealth.md +++ b/yellow-paper/docs/addresses-and-keys/diversified-and-stealth.md @@ -2,14 +2,19 @@ title: Diversified and Stealth Accounts --- -The [keys specification](./specification.md) describes derivation mechanisms for diversified and stealth public keys. However, the protocol requires users to interact with addresses. +The [keys specification](./keys.md) describes derivation mechanisms for diversified and stealth public keys. However, the protocol requires users to interact with addresses. ## Computing Addresses -To support diversified and stealth accounts, a user may compute the deterministic address for a given account contract that is deployed using the diversified or stealth public key, so a sender can interact with the resulting address even before the account contract is deployed. +To support diversified and stealth accounts, a user may compute the deterministic address for a given account contract that is deployed using a diversified or stealth public key, so a sender can interact with the resulting so-called "diversified" or "stealth" address even before the account contract is deployed. When the user wants to access the notes that were sent to the diversified or stealth address, they can deploy the contract at their address, and control it privately from their main account. + + ## Account Contract Pseudocode As an example implementation, account contracts for diversified and stealth accounts can be designed to require no private constructor or state, and delegate entrypoint access control to their master address. @@ -32,6 +37,11 @@ contract DiversifiedAccount Given the contract does not require initialization since it has no constructor, it can be used by its owner without being actually deployed, which reduces the setup cost. + + + + + ## Discarded Approaches An alternative approach was to introduce a new type of call, a diversified call, that would allow the caller to impersonate any address they can derive from their own, for an enshrined derivation mechanism. Account contracts could use this opcode, as opposed to a regular call, to issue calls on behalf on their diversified and stealth addresses. However, this approach failed to account for calls made back to the account contracts, in particular authwit checks. It also required protocol changes, introducing a new type of call which could be difficult to reason about, and increased attack surface. The only benefit over the approach chosen is that it would require one less extra function call to hop from the user's main account contract to the diversified or stealth one. diff --git a/yellow-paper/docs/addresses-and-keys/index.md b/yellow-paper/docs/addresses-and-keys/index.md index 89888dacf46..d9c2730d8fd 100644 --- a/yellow-paper/docs/addresses-and-keys/index.md +++ b/yellow-paper/docs/addresses-and-keys/index.md @@ -2,13 +2,19 @@ title: Addresses and Keys --- -Aztec has no concept of externally-owned accounts. Every address is meant to identify a smart contract in the network. Addresses are then a commitment to a contract class, a list of constructor arguments, and a set of keys. + + +Aztec has no concept of externally-owned accounts. Every address identifies a smart contract in the network. + +For end users to interact with the network, they'll most-likely need to [deploy](../contract-deployment/index.md) a so-called "account contract". + +Addresses are then a commitment to a contract class, a list of constructor arguments, and a set of keys. Keys in Aztec are used both for authorization and privacy. Authorization keys are managed by account contracts, and not mandated by the protocol. Each account contract may use different authorization keys, if at all, with different signing mechanisms. -Privacy keys are used for note encryption, tagging, and nullifying. These are also not enforced by the protocol. However, for facilitating composability, the protocol enshrines a set of well-known encryption and tagging mechanisms, that can be leveraged by applications as they interact with accounts. +Privacy keys are used for note encryption, tagging, and nullifying. These are also not enforced by the protocol. However, for facilitating composability, the protocol enshrines a set of enshrined encryption and tagging mechanisms, that can be leveraged by applications as they interact with accounts. -The [specification](./specification.md) covers the main requirements for addresses and keys, along with their specification and derivation mechanisms, while the [precompiles](./precompiles.md) section describes well-known contract addresses, with implementations defined by the protocol, used for note encryption and tagging. +The [requirements](./keys-requirements.md) section outlines the features that were sought when designing Aztec's addresses and keys. We then specify how [addresses](./address.md) are derived, as well as the default way in which [keys](./keys.md) will be derived. The [precompiles](./precompiles.md) section describes enshrined contract addresses, with implementations defined by the protocol, used for note encryption and tagging. Last, the [diversified and stealth accounts](./diversified-and-stealth.md) sections describe application-level recommendations for diversified and stealth accounts. diff --git a/yellow-paper/docs/addresses-and-keys/keys-requirements.md b/yellow-paper/docs/addresses-and-keys/keys-requirements.md new file mode 100644 index 00000000000..d7fa8ed9a52 --- /dev/null +++ b/yellow-paper/docs/addresses-and-keys/keys-requirements.md @@ -0,0 +1,186 @@ +--- +title: Requirements +description: Requirements which motivated Aztec's design for addresses and keys. +--- + +## Requirements for Keys + +### Scenario + +A common illustration in this document is Bob sending funds to Alice, by: + +- creating a "note" for her; +- committing to the contents of that note (a "note hash"); +- inserting that note hash into a utxo tree; +- encrypting the contents of that note for Alice; +- optionally encrypting the contents of that note for Bob's future reference; +- optionally deriving an additional "tag" (a.k.a. "clue") to accompany the ciphertexts for faster note discovery; +- broadcasting the resulting ciphertext(s) (and tag(s)); +- optionally identifying the tags; +- decrypting the ciphertexts; storing the note; and some time later spending (nullifying) the note. + +> Note: there is nothing to stop an app and wallet from implementing its own key derivation scheme. Nevertheless, we're designing a 'canonical' scheme that most developers and wallets can use. + +### Authorization keys + +Aztec has native account abstraction, so tx authentication is done via an account contract, meaning tx authentication can be implemented however the user sees fit. That is, authorization keys aren't specified at the protocol level. + +A tx authentication secret key is arguably the most important key to keep private, because knowledge of such a key could potentially enable an attacker to impersonate the user and execute a variety of functions on the network. + +**Requirements:** + +- A tx authentication secret key SHOULD NOT enter Aztec software, and SHOULD NOT enter a circuit. + - Reason: this is just best practice. + +### Master & Siloed Keys + +**Requirements:** + +- All keys must be re-derivable from a single `seed` secret. +- Users must have the option of keeping this `seed` offline, e.g. in a hardware wallet, or on a piece of paper. +- All master keys (for a particular user) must be linkable to a single address for that user. +- For each contract, a siloed set of all secret keys MUST be derivable. + - Reason: secret keys must be siloed, so that a malicious app circuit cannot access and emit (as an unencrypted event or as args to a public function) a user's master secret keys or the secret keys of other apps. +- Master _secret_ keys must not be passed into an app circuit, except for precompiles. + - Reason: a malicious app could broadcast these secret keys to the world. +- Siloed secret keys _of other apps_ must not be passed into an app circuit. + - Reason: a malicious app could broadcast these secret keys to the world. +- The PXE must prevent an app from accessing master secret keys. +- The PXE must prevent an app from accessing siloed secret keys that belong to another contract address. + - Note: To achieve this, the PXE simulator will need to check whether the bytecode being executed (that is requesting secret keys) actually exists at the contract address. +- There must be one and only one way to derive all (current\*) master keys, and all siloed keys, for a particular user address. + - For example, a user should not be able to derive multiple different outgoing viewing keys for a single incoming viewing key (note: this was a 'bug' that was fixed between ZCash Sapling and Orchard). + - \*"current", alludes to the possibility that the user might wish to support rotating keys, but only if one and only one set of keys is derivable as "current". +- All app-siloed keys can all be deterministically linked back to the user's address, without leaking important secrets to the app. + +#### Security assumptions + +- The Aztec private execution client (PXE), precompiled contracts (vetted application circuits), and the kernel circuit (a core protocol circuit) can be trusted with master secret keys (_except for_ the tx authorization secret key, whose security assumptions are abstracted-away to wallet designers). + +### Encryption and decryption + +Definitions (from the point of view of a user ("yourself")): + +- Incoming data: Data which has been created by someone else, and sent to yourself. +- Outgoing data: Data which has been sent to somebody else, from you. +- Internal Incoming data: Data which has been created by you, and has been sent to yourself. + - Note: this was an important observation by ZCash. Before this distinction, whenever a 'change' note was being created, it was being broadcast as incoming data, but that allowed a 3rd party who was only meant to have been granted access to view "incoming" data (and not "outgoing" data), was also able to learn that an "outgoing" transaction had taken place (including information about the notes which were spent). The addition of "internal incoming" keys enables a user to keep interactions with themselves private and separate from interactions with others. + +**Requirements:** + +- A user can derive app-siloed incoming internal and outgoing viewing keys. + - Reason: Allows users to share app-siloed keys to trusted 3rd parties such as auditors, scoped by app. + - Incoming viewing keys are not considered for siloed derivation due to the lack of a suitable public key derivation mechanism. +- A user can encrypt a record of any actions, state changes, or messages, to _themselves_, so that they may re-sync their entire history of actions from their `seed`. + +### Nullifier keys + +Derivation of a nullifier is app-specific; a nullifier is just a `field` (siloed by contract address), from the pov of the protocol. + +Many private application devs will choose to inject a secret "nullifier key" into a nullifier. Such a nullifier key would be tied to a user's public identifier (e.g. their address), and that identifier would be tied to the note being nullified (e.g. the note might contain that identifier). This is a common pattern in existing privacy protocols. Injecting a secret "nullifier key" in this way serves to hide what the nullifier is nullifying, and ensures the nullifier can only be derived by one person (assuming the nullifier key isn't leaked). + +> Note: not all nullifiers require injection of a secret _which is tied to a user's identity in some way_. Sometimes an app will need just need a guarantee that some value will be unique, and so will insert it into the nullifier tree. + +**Requirements:** + +- Support use cases where an app requires a secret "nullifier key" (linked to a user identity) to be derivable. + - Reason: it's a very common pattern. + +#### Is a nullifier key _pair_ needed? + +I.e. do we need both a nullifier secret key and a nullifier public key? Zcash sapling had both, but Zcash orchard (an upgrade) replaced the notion of a keypair with a single nullifier key. The [reason](https://zcash.github.io/orchard/design/keys.html) being: + +- _"[The nullifier secret key's (nsk's)] purpose in Sapling was as defense-in-depth, in case RedDSA [(the scheme used for signing txs, using the authentication secret key ask)] was found to have weaknesses; an adversary who could recover ask would not be able to spend funds. In practice it has not been feasible to manage nsk much more securely than a full viewing key [(dk, ak, nk, ovk)], as the computational power required to generate Sapling proofs has made it necessary to perform this step [(deriving nk from nsk)] on the same device that is creating the overall transaction (rather than on a more constrained device like a hardware wallet). We are also more confident in RedDSA now."_ + +A nullifier public key might have the benefit (in Aztec) that a user could (optionally) provide their nullifier key nk to some 3rd party, to enable that 3rd party to see when the user's notes have been nullified for a particular app, without having the ability to nullify those notes. + +- This presumes that within a circuit, the nk (not a public key; still secret!) would be derived from an nsk, and the nk would be injected into the nullifier. +- BUT, of course, it would be BAD if the nk were derivable as a bip32 normal child, because then everyone would be able to derive the nk from the master key, and be able to view whenever a note is nullified! +- The nk would need to ba a hardened key (derivable only from a secret). + +Given that it's acceptable to ZCash Orchard, we accept that a nullifier master secret key may be 'seen' by Aztec software. + +### Auditability + +Some app developers will wish to give users the option of sharing private transaction details with a trusted 3rd party. + +> Note: The block hashes tree will enable a user to prove many things about their historical transaction history, including historical encrypted event logs. This feature will open up exciting audit patterns, where a user will be able to provably respond to questions without necessarily revealing their private data. However, sometimes this might be an inefficient pattern; in particular when a user is asked to prove a negative statement (e.g. "prove that you've never owned a rock NFT"). Proving such negative statements might require the user to execute an enormous recursive function to iterate through the entire tx history of the network, for example: proving that, out of all the encrypted events that the user _can_ decrypt, none of them relate to ownership of a rock NFT. Given this (possibly huge) inefficiency, these key requirements include the more traditional ability to share certain keys with a trusted 3rd party. + +**Requirements:** + +- "Shareable" secret keys. + - A user can optionally share "shareable" secret keys, to enable a 3rd party to decrypt the following data: + - Outgoing data, across all apps + - Outgoing data, siloed for a single app + - Incoming internal data, across all apps + - Incoming internal data, siloed for a single app + - Incoming data, across all apps + - Incoming data, siloed for a single app, is **not** required due to lack of a suitable derivation scheme + - Shareable nullifier key. + - A user can optionally share a "shareable" nullifier key, which would enable a trusted 3rd party to see _when_ a particular note hash has been nullified, but would not divulge the contents of the note, or the circumstances under which the note was nullified (as such info would only be gleanable with the shareable viewing keys). + - Given one (or many) shareable keys, a 3rd part MUST NOT be able to derive any of a user's other secret keys; be they shareable or non-shareable. + - Further, they must not be able to derive any relationships _between_ other keys. +- No impersonation. + - The sharing of any (or all) "shareable" key(s) MUST NOT enable the trusted 3rd party to perform any actions on the network, on behalf of the user. + - The sharing of a "shareable" outgoing viewing secret (and a "shareable" _internal_ incoming viewing key) MUST NOT enable the trusted 3rd party to emit encrypted events that could be perceived as "outgoing data" (or internal incoming data) originating from the user. +- Control over incoming/outgoing data. + - A user can choose to only give incoming data viewing rights to a 3rd party. (Gives rise to incoming viewing keys). + - A user can choose to only give outgoing data viewing rights to a 3rd party. (Gives rise to outgoing viewing keys). + - A user can choose to keep interactions with themselves private and distinct from the viewability of interactions with other parties. (Gives rise to _internal_ incoming viewing keys). + +### Sending funds before deployment + +**Requirements:** + +- A user can generate an address to which funds (and other notes) can be sent, without that user having ever interacted with the network. + - To put it another way: A user can be sent money before they've interacted with the Aztec network (i.e. before they've deployed an account contract). e.g their incoming viewing key can be derived. +- An address (user identifier) can be derived deterministically, before deploying an account contract. + +### Note Discovery + +**Requirements:** + +- A user should be able to discover which notes belong to them, without having to trial-decrypt every single note broadcasted on chain. +- Users should be able to opt-in to using new note discovery mechanisms as they are made available in the protocol. + +#### Tag Hopping + +Given that this is our best-known approach, we include some requirements relating to it: + +**Requirements:** + +- A user Bob can non-interactively generate a sequence of tags for some other user Alice, and non-interactively communicate that sequencer of tags to Alice. +- If a shared secret (that is used for generating a sequence of tags) is leaked, Bob can non-interactively generate and communicate a new sequence of tags to Alice, without requiring Bob nor Alice to rotate their keys. + - Note: if the shared secret is leaked through Bob/Alice accidentally leaking one of their keys, then they might need to actually rotate their keys. + +### Constraining key derivations + +- An app has the ability to constrain the correct encryption and/or note discovery tagging scheme. +- An app can _choose_ whether or not to constrain the correct encryption and/or note discovery tagging scheme. + - Reason: constraining these computations (key derivations, encryption algorithms, tag derivations) will be costly (in terms of constraints), and some apps might not need to constrain it (e.g. zcash does not constrain correct encryption). + +### Rotating keys + +- A user should be able to rotate their set of keys, without having to deploy a new account contract. + - Reason: keys can be compromised, and setting up a new identity is costly, since the user needs to migrate all their assets. Rotating encryption keys allows the user to regain privacy for all subsequent interactions while keeping their identity. + - This requirement causes a security risk when applied to nullifier keys. If a user can rotate their nullifier key, then the nullifier for any of their notes changes, so they can re-spend any note. Rotating nullifier keys requires the nullifier public key, or at least an identifier of it, to be stored as part of the note. Alternatively, this requirement can be removed for nullifier keys, which are not allowed to be rotated. + + + +### Diversified Keys + +- Alice can derive a diversified address; a random-looking address which she can (interactively) provide to Bob, so that Bob may send her funds (and general notes). + - Reason: By having the recipient derive a distinct payment address _per counterparty_, and then interactively provide that address to the sender, means that if two counterparties collude, they won't be able to convince the other that they both interacted with the same recipient. +- Random-looking addresses can be derived from a 'main' address, so that private to public function calls don't reveal the true `msg_sender`. These random-looking addresses can be provably linked back to the 'main' address. + > Note: both diversified and stealth addresses would meet this requirement. +- Distributing many diversified addresses must not increase the amount of time needed to scan the blockchain (they must all share a single set of viewing keys). + +### Stealth Addresses + +Not to be confused with diversified addresses. A diversified address is generated by the recipient, and interactively given to a sender, for the sender to then use. But a stealth address is generated by the _sender_, and non-interactively shared with the recipient. + +Requirement: + +- Random-looking addresses can be derived from a 'main' address, so that private -> public function calls don't reveal the true `msg_sender`. These random-looking addresses can be provably linked back to the 'main' address. + > Note: both diversified and stealth addresses would meet this requirement. +- Unlimited random-looking addresses can be non-interactively derived by a sender for a particular recipient, in such a way that the recipient can use one set of keys to decrypt state changes or change states which are 'owned' by that stealth address. diff --git a/yellow-paper/docs/addresses-and-keys/specification.md b/yellow-paper/docs/addresses-and-keys/keys.md similarity index 57% rename from yellow-paper/docs/addresses-and-keys/specification.md rename to yellow-paper/docs/addresses-and-keys/keys.md index d04e3f2aa76..4e1885aaefd 100644 --- a/yellow-paper/docs/addresses-and-keys/specification.md +++ b/yellow-paper/docs/addresses-and-keys/keys.md @@ -1,8 +1,10 @@ --- -title: Specification -description: Specification of address format in the protocol, default privacy keys format and derivation, and nullifier derivation. +title: Default Keys Specification +description: Specification for default privacy keys format and derivation, and nullifier derivation. --- + + $$ \gdef\sk{\color{red}{sk}} @@ -91,207 +93,8 @@ $$ $$ -## Requirements for Keys - -### Scenario - -A common illustration in this document is Bob sending funds to Alice, by: - -- creating a "note" for her; -- committing to the contents of that note (a "note hash"); -- inserting that note hash into a utxo tree; -- encrypting the contents of that note for Alice; -- optionally encrypting the contents of that note for Bob's future reference; -- optionally deriving an additional "tag" (a.k.a. "clue") to accompany the ciphertexts for faster note discovery; -- broadcasting the resulting ciphertext(s) (and tag(s)); -- optionally identifying the tags; -- decrypting the ciphertexts; storing the note; and some time later spending (nullifying) the note. - -> Note: there is nothing to stop an app and wallet from implementing its own key derivation scheme. Nevertheless, we're designing a 'canonical' scheme that most developers and wallets can use. - -### Authorization keys - -Aztec has native account abstraction, so tx authentication is done via an account contract, meaning tx authentication can be implemented however the user sees fit. That is, authorization keys aren't specified at the protocol level. - -A tx authentication secret key is arguably the most important key to keep private, because knowledge of such a key could potentially enable an attacker to impersonate the user and execute a variety of functions on the network. - -**Requirements:** - -- A tx authentication secret key SHOULD NOT enter Aztec software, and SHOULD NOT enter a circuit. - - Reason: this is just best practice. - -### Master & Siloed Keys - -**Requirements:** - -- All keys must be re-derivable from a single `seed` secret. -- Users must have the option of keeping this `seed` offline, e.g. in a hardware wallet, or on a piece of paper. -- All master keys (for a particular user) must be linkable to a single address for that user. -- For each contract, a siloed set of all secret keys MUST be derivable. - - Reason: secret keys must be siloed, so that a malicious app circuit cannot access and emit (as an unencrypted event or as args to a public function) a user's master secret keys or the secret keys of other apps. -- Master _secret_ keys must not be passed into an app circuit, except for precompiles. - - Reason: a malicious app could broadcast these secret keys to the world. -- Siloed secret keys _of other apps_ must not be passed into an app circuit. - - Reason: a malicious app could broadcast these secret keys to the world. -- The PXE must prevent an app from accessing master secret keys. -- The PXE must prevent an app from accessing siloed secret keys that belong to another contract address. - - Note: To achieve this, the PXE simulator will need to check whether the bytecode being executed (that is requesting secret keys) actually exists at the contract address. -- There must be one and only one way to derive all (current\*) master keys, and all siloed keys, for a particular user address. - - For example, a user should not be able to derive multiple different outgoing viewing keys for a single incoming viewing key (note: this was a 'bug' that was fixed between ZCash Sapling and Orchard). - - \*"current", alludes to the possibility that the user might wish to support rotating keys, but only if one and only one set of keys is derivable as "current". -- All app-siloed keys can all be deterministically linked back to the user's address, without leaking important secrets to the app. - -#### Security assumptions - -- The Aztec private execution client (PXE), precompiled contracts (vetted application circuits), and the kernel circuit (a core protocol circuit) can be trusted with master secret keys (_except for_ the tx authorization secret key, whose security assumptions are abstracted-away to wallet designers). - -### Encryption and decryption - -Definitions (from the point of view of a user ("yourself")): - -- Incoming data: Data which has been created by someone else, and sent to yourself. -- Outgoing data: Data which has been sent to somebody else, from you. -- Internal Incoming data: Data which has been created by you, and has been sent to yourself. - - Note: this was an important observation by ZCash. Before this distinction, whenever a 'change' note was being created, it was being broadcast as incoming data, but that allowed a 3rd party who was only meant to have been granted access to view "incoming" data (and not "outgoing" data), was also able to learn that an "outgoing" transaction had taken place (including information about the notes which were spent). The addition of "internal incoming" keys enables a user to keep interactions with themselves private and separate from interactions with others. - -**Requirements:** - -- A user can derive app-siloed incoming internal and outgoing viewing keys. - - Reason: Allows users to share app-siloed keys to trusted 3rd parties such as auditors, scoped by app. - - Incoming viewing keys are not considered for siloed derivation due to the lack of a suitable public key derivation mechanism. -- A user can encrypt a record of any actions, state changes, or messages, to _themselves_, so that they may re-sync their entire history of actions from their `seed`. - -### Nullifier keys - -Derivation of a nullifier is app-specific; a nullifier is just a `field` (siloed by contract address), from the pov of the protocol. - -Many private application devs will choose to inject a secret "nullifier key" into a nullifier. Such a nullifier key would be tied to a user's public identifier (e.g. their address), and that identifier would be tied to the note being nullified (e.g. the note might contain that identifier). This is a common pattern in existing privacy protocols. Injecting a secret "nullifier key" in this way serves to hide what the nullifier is nullifying, and ensures the nullifier can only be derived by one person (assuming the nullifier key isn't leaked). - -> Note: not all nullifiers require injection of a secret _which is tied to a user's identity in some way_. Sometimes an app will need just need a guarantee that some value will be unique, and so will insert it into the nullifier tree. - -**Requirements:** - -- Support use cases where an app requires a secret "nullifier key" (linked to a user identity) to be derivable. - - Reason: it's a very common pattern. - -#### Is a nullifier key _pair_ needed? - -I.e. do we need both a nullifier secret key and a nullifier public key? Zcash sapling had both, but Zcash orchard (an upgrade) replaced the notion of a keypair with a single nullifier key. The [reason](https://zcash.github.io/orchard/design/keys.html) being: - -- _"[The nullifier secret key's (nsk's)] purpose in Sapling was as defense-in-depth, in case RedDSA [(the scheme used for signing txs, using the authentication secret key ask)] was found to have weaknesses; an adversary who could recover ask would not be able to spend funds. In practice it has not been feasible to manage nsk much more securely than a full viewing key [(dk, ak, nk, ovk)], as the computational power required to generate Sapling proofs has made it necessary to perform this step [(deriving nk from nsk)] on the same device that is creating the overall transaction (rather than on a more constrained device like a hardware wallet). We are also more confident in RedDSA now."_ - -A nullifier public key might have the benefit (in Aztec) that a user could (optionally) provide their nullifier key nk to some 3rd party, to enable that 3rd party to see when the user's notes have been nullified for a particular app, without having the ability to nullify those notes. - -- This presumes that within a circuit, the nk (not a public key; still secret!) would be derived from an nsk, and the nk would be injected into the nullifier. -- BUT, of course, it would be BAD if the nk were derivable as a bip32 normal child, because then everyone would be able to derive the nk from the master key, and be able to view whenever a note is nullified! -- The nk would need to ba a hardened key (derivable only from a secret). - -Given that it's acceptable to ZCash Orchard, we accept that a nullifier master secret key may be 'seen' by Aztec software. - -### Auditability - -Some app developers will wish to give users the option of sharing private transaction details with a trusted 3rd party. - -> Note: The block hashes tree will enable a user to prove many things about their historical transaction history, including historical encrypted event logs. This feature will open up exciting audit patterns, where a user will be able to provably respond to questions without necessarily revealing their private data. However, sometimes this might be an inefficient pattern; in particular when a user is asked to prove a negative statement (e.g. "prove that you've never owned a rock NFT"). Proving such negative statements might require the user to execute an enormous recursive function to iterate through the entire tx history of the network, for example: proving that, out of all the encrypted events that the user _can_ decrypt, none of them relate to ownership of a rock NFT. Given this (possibly huge) inefficiency, these key requirements include the more traditional ability to share certain keys with a trusted 3rd party. - -**Requirements:** - -- "Shareable" secret keys. - - A user can optionally share "shareable" secret keys, to enable a 3rd party to decrypt the following data: - - Outgoing data, across all apps - - Outgoing data, siloed for a single app - - Incoming internal data, across all apps - - Incoming internal data, siloed for a single app - - Incoming data, across all apps - - Incoming data, siloed for a single app, is **not** required due to lack of a suitable derivation scheme - - Shareable nullifier key. - - A user can optionally share a "shareable" nullifier key, which would enable a trusted 3rd party to see _when_ a particular note hash has been nullified, but would not divulge the contents of the note, or the circumstances under which the note was nullified (as such info would only be gleanable with the shareable viewing keys). - - Given one (or many) shareable keys, a 3rd part MUST NOT be able to derive any of a user's other secret keys; be they shareable or non-shareable. - - Further, they must not be able to derive any relationships _between_ other keys. -- No impersonation. - - The sharing of any (or all) "shareable" key(s) MUST NOT enable the trusted 3rd party to perform any actions on the network, on behalf of the user. - - The sharing of a "shareable" outgoing viewing secret (and a "shareable" _internal_ incoming viewing key) MUST NOT enable the trusted 3rd party to emit encrypted events that could be perceived as "outgoing data" (or internal incoming data) originating from the user. -- Control over incoming/outgoing data. - - A user can choose to only give incoming data viewing rights to a 3rd party. (Gives rise to incoming viewing keys). - - A user can choose to only give outgoing data viewing rights to a 3rd party. (Gives rise to outgoing viewing keys). - - A user can choose to keep interactions with themselves private and distinct from the viewability of interactions with other parties. (Gives rise to _internal_ incoming viewing keys). - -### Sending funds before deployment - -**Requirements:** - -- A user can generate an address to which funds (and other notes) can be sent, without that user having ever interacted with the network. - - To put it another way: A user can be sent money before they've interacted with the Aztec network (i.e. before they've deployed an account contract). e.g their incoming viewing key can be derived. -- An address (user identifier) can be derived deterministically, before deploying an account contract. - -### Note Discovery - -**Requirements:** - -- A user should be able to discover which notes belong to them, without having to trial-decrypt every single note broadcasted on chain. -- Users should be able to opt-in to using new note discovery mechanisms as they are made available in the protocol. - -#### Tag Hopping - -Given that this is our best-known approach, we include some requirements relating to it: - -**Requirements:** - -- A user Bob can non-interactively generate a sequence of tags for some other user Alice, and non-interactively communicate that sequencer of tags to Alice. -- If a shared secret (that is used for generating a sequence of tags) is leaked, Bob can non-interactively generate and communicate a new sequence of tags to Alice, without requiring Bob nor Alice to rotate their keys. - - Note: if the shared secret is leaked through Bob/Alice accidentally leaking one of their keys, then they might need to actually rotate their keys. - -### Constraining key derivations - -- An app has the ability to constrain the correct encryption and/or note discovery tagging scheme. -- An app can _choose_ whether or not to constrain the correct encryption and/or note discovery tagging scheme. - - Reason: constraining these computations (key derivations, encryption algorithms, tag derivations) will be costly (in terms of constraints), and some apps might not need to constrain it (e.g. zcash does not constrain correct encryption). - -### Rotating keys - -- A user should be able to rotate their set of keys, without having to deploy a new account contract. - - Reason: keys can be compromised, and setting up a new identity is costly, since the user needs to migrate all their assets. Rotating encryption keys allows the user to regain privacy for all subsequent interactions while keeping their identity. - - This requirement causes a security risk when applied to nullifier keys. If a user can rotate their nullifier key, then the nullifier for any of their notes changes, so they can re-spend any note. Rotating nullifier keys requires the nullifier public key, or at least an identifier of it, to be stored as part of the note. Alternatively, this requirement can be removed for nullifier keys, which are not allowed to be rotated. - - - -### Diversified Keys - -- Alice can derive a diversified address; a random-looking address which she can (interactively) provide to Bob, so that Bob may send her funds (and general notes). - - Reason: By having the recipient derive a distinct payment address _per counterparty_, and then interactively provide that address to the sender, means that if two counterparties collude, they won't be able to convince the other that they both interacted with the same recipient. -- Random-looking addresses can be derived from a 'main' address, so that private to public function calls don't reveal the true `msg_sender`. These random-looking addresses can be provably linked back to the 'main' address. - > Note: both diversified and stealth addresses would meet this requirement. -- Distributing many diversified addresses must not increase the amount of time needed to scan the blockchain (they must all share a single set of viewing keys). - -### Stealth Addresses - -Not to be confused with diversified addresses. A diversified address is generated by the recipient, and interactively given to a sender, for the sender to then use. But a stealth address is generated by the _sender_, and non-interactively shared with the recipient. - -Requirement: - -- Random-looking addresses can be derived from a 'main' address, so that private -> public function calls don't reveal the true `msg_sender`. These random-looking addresses can be provably linked back to the 'main' address. - > Note: both diversified and stealth addresses would meet this requirement. -- Unlimited random-looking addresses can be non-interactively derived by a sender for a particular recipient, in such a way that the recipient can use one set of keys to decrypt state changes or change states which are 'owned' by that stealth address. - -## Notation - -- An upper-case first letter is used for elliptic curve points (all on the Grumpkin curve) (e.g. $\Ivpkm$). -- A lower-case first letter is used for scalars. (TODO: improve this. Some hash outputs might be 256-bit instead of a field element, for example). -- $G$ is a generator point on the Grumpkin curve. -- A "cdot" ("$\cdot$") is used to denote scalar multiplication. -- "$+$" should be clear from context whether it's field or point addition. -- A function 'h()' is a placeholder for some as-yet-undecided hash function or pseudo-random function, the choice of which is tbd. Note: importantly, 'h()' is lazy notation, in that not all instances of h() imply the same hash function should be used. -- The string "?" is a lazy placeholder domain separator. -- A function $encrypt_{enc\_key}^{pub\_key}(plaintext)$ is a placeholder for some as-yet-undecided symmetric encryption function. The $enc\_key$ subscript indicates the encryption key, and the superscript $pub\_key$ is an occasional reminder of the public key of the recipient. -- A function $decrypt_{enc\_key}(ciphertext)$ is the counterpart to the $encrypt()$ placeholder function. -- A subscript $m$ is used on keys to mean "master key". -- A subscript $app$ is used on keys to mean "an app-siloed key, derived from the master key and the app's contract address". -- A subscript $d$ is used on keys to mean "diversified". Although note: a diversifier value of $d = 1$ implies no diversification, as will often be the case in practice. - ## Colour Key -> Haha. Key. Good one. - - $\color{green}{green}$ = Publicly shareable information. - $\color{red}{red}$ = Very secret information. A user MUST NOT share this information. - TODO: perhaps we distinguish between information that must not be shared to prevent theft, and information that must not be shared to preserve privacy? @@ -325,55 +128,7 @@ $\Ovpkm$ | $\ovskm \cdot G$ | outgoing viewing public key | | Only included so t > \*These keys could also be safely passed into the Kernel circuit, but there's no immediately obvious use, so "K" has been omitted, to make design intentions clearer. - - -## Address - -An address is computed as the hash of the following fields: - - -| Field | Type | Description | -|----------|----------|----------| -| `salt` | `Field` | User-generated pseudorandom value for uniqueness. | -| `deployer` | `AztecAddress` | Optional address of the deployer of the contract. | -| `contract_class_id` | `Field` | Identifier of the contract class for this instance. | -| `initialization_hash` | `Field` | Hash of the selector and arguments to the constructor. | -| `portal_contract_address` | `EthereumAddress` | Address of the L1 portal contract, zero if none. | -| `public_keys_hash` | `Field` | Hash of the struct of public keys used for encryption and nullifying by this contract, zero if no public keys. | - -Storing these fields in the address preimage allows any part of the protocol to check them by recomputing the hash and verifying that the address matches. Examples of these checks are: -- Sending an encrypted note to an undeployed account, which requires the sender app to check the recipient's public key given their address. This scenario also requires the recipient to share with the sender their public key and rest of preimage. -- Having the kernel circuit verify that the code executed at a given address matches the one from the class. -- Asserting that the initialization hash matches the function call in the contract constructor. -- Checking the portal contract address when sending a cross-chain message. - -:::warning -We may remove the `portal_contract_address` as a first-class citizen. -::: - -The hashing scheme for the address should then ensure that checks that are more frequent can be done cheaply, and that data shared out of band is kept manageable. We define the hash to be computed as follows: - -``` -salted_initialization_hash = pedersen([salt, initialization_hash, deployer as Field, portal_contract_address as Field], GENERATOR__SALTED_INITIALIZATION_HASH) -partial_address = pedersen([contract_class_id, salted_initialization_hash], GENERATOR__CONTRACT_PARTIAL_ADDRESS_V1) -address = pedersen([public_keys_hash, partial_address], GENERATOR__CONTRACT_ADDRESS_V1) -``` - -The `public_keys` array can vary depending on the format of keys used by the address, but it is suggested it includes the master keys defined above: $\Npkm$, $\Tpkm$, $\Ivpkm$, $\Ovpkm$. A suggested hashing is: -``` -public_keys_hash = pedersen([ - nullifier_pubkey.x, nullifier_pubkey.y, - tagging_pubkey.x, tagging_pubkey.y, - incoming_view_pubkey.x, incoming_view_pubkey.y, - outgoing_view_pubkey.x, outgoing_view_pubkey.y -], GENERATOR__PUBLIC_KEYS) -``` - -This recommended hash format is compatible with the [encryption precompiles](./precompiles.md#encryption-and-tagging-precompiles) initially defined in the protocol and advertised in the canonical [registry](../private-message-delivery/registry.md) for private message delivery. An address that chooses to use a different format for its keys will not be compatible with apps that rely on the registry for note encryption. Nevertheless, new precompiles introduced in future versions of the protocol could use different public keys formats. - - - -## Derive siloed keys +## Deriving siloed keys ### Nullifier keys @@ -464,7 +219,7 @@ This can be done by either: - Generating a very basic sequence of tags $\tagg_{app, i}^{Bob \rightarrow Bob} = h(\ovskapp, i)$ (at the app level) and $\tagg_{m, i}^{Bob \rightarrow Bob} = h(\ovskm, i)$. - Note: In the case of deriving app-specific sequences of tags, Bob might wish to also encrypt the app*address as a ciphertext header (and attach a master tag $\tagg*{m, i}^{Bob \rightarrow Bob}$), to remind himself of the apps that he should derive tags _for_. -## Derive diversified public keys +## Deriving diversified public keys A diversified public key can be derived from Alice's keys, to enhance Alice's transaction privacy. If Alice's counterparties' databases are compromised, it enables Alice to retain privacy from such leakages. Diversified public keys are used for generating diversified addresses. @@ -485,7 +240,7 @@ $\Ivpkmd$ | $\ivskm \cdot \Gd$ | Diversified incoming viewing public key | > Notice: when $\d = 1$, $\Ivpkmd = \Ivpkm$. Often, it will be unncessary to diversify the below data, but we keep $\d$ around for the most generality. -## Derive stealth public keys +## Deriving stealth public keys > All of the key information below is Alice's @@ -530,7 +285,7 @@ $\Pkappdstealth$ | $\Ivpkappdstealth$ | Alias: "Alice's Stealth Public Key" | -## Derive nullifier +## Deriving a nullifier within an app contract Let's assume a developer wants a nullifier of a note to be derived as: diff --git a/yellow-paper/docs/addresses-and-keys/precompiles.md b/yellow-paper/docs/addresses-and-keys/precompiles.md index 1412f9d0abb..093ff92fc4d 100644 --- a/yellow-paper/docs/addresses-and-keys/precompiles.md +++ b/yellow-paper/docs/addresses-and-keys/precompiles.md @@ -1,25 +1,32 @@ --- title: Precompiles -sidebar_position: 2 --- -Precompiled contracts, which borrow their name from Ethereum's, are contracts not deployed by users but defined at the protocol level. These contracts and their classes are assigned well-known low-number addresses and identifiers, and their implementation is subject to change via protocol upgrades. Precompiled contracts in Aztec are implemented as a set of circuits, one for each function they expose, like user-defined private contracts. Precompiles may make use of the local PXE oracle. Note that, unlike user-defined contracts, the address of a precompiled contract instance and the identifier of its class both have no known preimage. + -Rationale for precompiled contracts is to provide a set of vetted primitives for note encryption and tagging that applications can use safely. These primitives are guaranteed to be always satisfiable when called with valid arguments. This allows account contracts to choose their preferred method of encryption and tagging from any primitive in this set, and application contracts to call into them without the risk of calling into a untrusted code, which could potentially halt the execution flow via an unsatisfiable constrain. Furthermore, by exposing these primitives in a reserved set of well-known addresses, applications can be forward-compatible and incorporate new encryption and tagging methods as accounts opt into them. +Precompiled contracts, which borrow their name from Ethereum's, are contracts not deployed by users but defined at the protocol level. These contract [instances](../contract-deployment/instances.md) and their [classes](../contract-deployment/classes.md) are assigned well-known low-number addresses and identifiers, and their implementation is subject to change via protocol upgrades. Precompiled contracts in Aztec are implemented as a set of circuits, one for each function they expose, like user-defined private contracts. Precompiles may make use of the local PXE oracle. + +Note that, unlike user-defined contracts, the address of a precompiled [contract instance](../contract-deployment/instances.md) and the [identifier of its class](../contract-deployment/classes.md#class-identifier) both have no known preimage. + +The rationale for precompiled contracts is to provide a set of vetted primitives for [note encryption](../private-message-delivery/encryption-and-decryption.md) and [tagging](../private-message-delivery/note-discovery.md) that applications can use safely. These primitives are guaranteed to be always-satisfiable when called with valid arguments. This allows account contracts to choose their preferred method of encryption and tagging from any primitive in this set, and application contracts to call into them without the risk of calling into a untrusted code, which could potentially halt the execution flow via an unsatisfiable constraint. Furthermore, by exposing these primitives in a reserved set of well-known addresses, applications can be forward-compatible and incorporate new encryption and tagging methods as accounts opt into them. ## Constants -- `ENCRYPTION_BATCH_SIZES=[4, 16, 32]`: Defines what max batch sizes are supported in precompiled encryption methods. +- `ENCRYPTION_BATCH_SIZES=[4, 8, 16, 32]`: Defines what max [batch sizes](../calls/batched-calls.md) are supported in precompiled encryption methods. - `ENCRYPTION_PRECOMPILE_ADDRESS_RANGE=0x00..0xFFFF`: Defines the range of addresses reserved for precompiles used for encryption and tagging. - `MAX_PLAINTEXT_LENGTH`: Defines the maximum length of a plaintext to encrypt. -- `MAX_CYPHERTEXT_LENGTH`: Defines the maximum length of a returned encrypted cyphertext. -- `MAX_TAGGED_CYPHERTEXT_LENGTH`: Defines the maximum length of a returned encrypted cyphertext prefixed with a note tag. +- `MAX_CIPHERTEXT_LENGTH`: Defines the maximum length of a returned encrypted ciphertext. +- `MAX_TAGGED_CIPHERTEXT_LENGTH`: Defines the maximum length of a returned encrypted ciphertext prefixed with a note tag. + + ## Encryption and tagging precompiles -All precompiles in the address range `ENCRYPTION_PRECOMPILE_ADDRESS_RANGE` are reserved for encryption and tagging. Application contracts can expected to call into these contracts with note plaintext, recipients, and public keys. To facilitate forward compatibility, all unassigned addresses within the range expose the functions below as no-ops, meaning that no actions will be executed when calling into them. +All precompiles in the address range `ENCRYPTION_PRECOMPILE_ADDRESS_RANGE` are reserved for encryption and tagging. Application contracts can expected to call into these contracts with note plaintext(s), recipient address(es), and public key(s). To facilitate forward compatibility, all unassigned addresses within the range expose the functions below as no-ops, meaning that no actions will be executed when calling into them. + + -All functions in these precompiles accept a `PublicKeys` struct which contains the user advertised public keys. The structure of each of the public keys included can change from one encryption method to another, with the exception of the `nullifier_key` which is always restricted to a single field element. For forward compatibility, the precompiles interface accepts a hash of the public keys, which can be expanded within each method via an oracle call. +All functions in these precompiles accept a `PublicKeys` struct which contains the user-advertised public keys. The structure of each of the public keys included can change from one encryption method to another, with the exception of the `nullifier_key` which is always restricted to a single field element. For forward compatibility, the precompiles interface accepts a hash of the public keys, which can be expanded within each method via an oracle call. ``` struct PublicKeys: @@ -48,36 +55,36 @@ validate_keys(public_keys_hash: Field): bool Returns true if the set of public keys represented by `public_keys` is valid for this encryption and tagging mechanism. The precompile must guarantee that any of its methods must succeed if called with a set of public keys deemed as valid. This method returns `false` for undefined precompiles. ``` -encrypt(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_CYPHERTEXT_LENGTH] +encrypt(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_CIPHERTEXT_LENGTH] ``` -Encrypts the given plaintext using the provided public keys, and returns the encrypted cyphertext. +Encrypts the given plaintext using the provided public keys, and returns the encrypted ciphertext. ``` -encrypt_and_tag(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_TAGGED_CYPHERTEXT_LENGTH] +encrypt_and_tag(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_TAGGED_CIPHERTEXT_LENGTH] ``` Encrypts and tags the given plaintext using the provided public keys, and returns the encrypted note prefixed with its tag for note discovery. ``` -encrypt_and_broadcast(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_TAGGED_CYPHERTEXT_LENGTH] +encrypt_and_broadcast(public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH]): Field[MAX_TAGGED_CIPHERTEXT_LENGTH] ``` Encrypts and tags the given plaintext using the provided public keys, broadcasts them as an event, and returns the encrypted note prefixed with its tag for note discovery. This functions should be invoked via a [delegate call](../calls/delegate-calls.md), so that the broadcasted event is emitted as if it were from the caller contract. ``` -encrypt([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_CYPHERTEXT_LENGTH][N] -encrypt_and_tag([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_TAGGED_CYPHERTEXT_LENGTH][N] -encrypt_and_broadcast([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_TAGGED_CYPHERTEXT_LENGTH][N] +encrypt([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_CIPHERTEXT_LENGTH][N] +encrypt_and_tag([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_TAGGED_CIPHERTEXT_LENGTH][N] +encrypt_and_broadcast([call_context: CallContext, public_keys_hash: Field, encryption_type: EncryptionType, recipient: AztecAddress, plaintext: Field[MAX_PLAINTEXT_LENGTH] ][N]): Field[MAX_TAGGED_CIPHERTEXT_LENGTH][N] ``` Batched versions of the methods above, which accept an array of `N` tuples of public keys, recipient, and plaintext to encrypt in batch. Precompiles expose instances of this method for multiple values of `N` as defined by `ENCRYPTION_BATCH_SIZES`. Values in the batch with zeroes are skipped. These functions are intended to be used in [batched calls](../calls/batched-calls.md). ``` -decrypt(public_keys_hash: Field, encryption_type: EncryptionType, owner: AztecAddress, cyphertext: Field[MAX_CYPHERTEXT_LENGTH]): Field[MAX_PLAINTEXT_LENGTH] +decrypt(public_keys_hash: Field, encryption_type: EncryptionType, owner: AztecAddress, ciphertext: Field[MAX_CIPHERTEXT_LENGTH]): Field[MAX_PLAINTEXT_LENGTH] ``` -Decrypts the given cyphertext, encrypted for the provided owner. Instead of receiving the decryption key, this method triggers an oracle call to fetch the private decryption key directly from the local PXE and validates it against the supplied public key, in order to avoid leaking a user secret to untrusted application code. This method is intended for provable decryption use cases. +Decrypts the given ciphertext, encrypted for the provided owner. Instead of receiving the decryption key, this method triggers an oracle call to fetch the private decryption key directly from the local PXE and validates it against the supplied public key, in order to avoid leaking a user secret to untrusted application code. This method is intended for provable decryption use cases. ## Encryption strategies @@ -85,7 +92,7 @@ List of encryption strategies implemented by precompiles: ### AES128 -Uses AES128 for encryption, by generating an AES128 symmetric key and an IV from a shared secret derived from the recipient's public key and an ephemeral keypair. Requires that the recipient's keys are points in the Grumpkin curve. The output of the encryption is the concatenation of the encrypted cyphertext and the ephemeral public key. +Uses AES128 for encryption, by generating an AES128 symmetric key and an IV from a shared secret derived from the recipient's public key and an ephemeral keypair. Requires that the recipient's keys are points in the Grumpkin curve. The output of the encryption is the concatenation of the encrypted ciphertext and the ephemeral public key. Pseudocode for the encryption process: @@ -100,11 +107,11 @@ encrypt(plaintext, recipient_public_key): Pseudocode for the decryption process: ``` -decrypt(cyphertext, recipient_private_key): - ephemeral_public_key = cyphertext[0:64] +decrypt(ciphertext, recipient_private_key): + ephemeral_public_key = ciphertext[0:64] shared_secret = ephemeral_public_key * recipient_private_key [aes_key, aes_iv] = sha256(shared_secret ++ [0x01]) - return aes_decrypt(aes_key, aes_iv, cyphertext[64:]) + return aes_decrypt(aes_key, aes_iv, ciphertext[64:]) ``` @@ -142,7 +149,7 @@ When Alice wants to send a message to Bob for the first time: 3. Alice's PXE looks up the shared secret which doesn't exist since this is their first interaction. 4. Alice's PXE generates a random shared secret, and stores it associated Bob along with `counter=1`. 5. The precompile makes a call to the `Handshake` contract that emits the shared secret, encrypted for Bob and optionally Alice. -6. The precompile computes `new_tag = hash(alice, bob, secret, counter)`, emits it as a nullifier, and prepends it to the note cyphertext before broadcasting it. +6. The precompile computes `new_tag = hash(alice, bob, secret, counter)`, emits it as a nullifier, and prepends it to the note ciphertext before broadcasting it. For all subsequent messages: @@ -150,15 +157,16 @@ For all subsequent messages: 2. The precompile makes an oracle call to `getSharedSecret(Alice, Bob)`. 3. Alice's PXE looks up the shared secret and returns it, along with the current value for `counter`, and locally increments `counter`. 4. The precompile computes `previous_tag = hash(alice, bob, secret, counter)`, and performs a merkle membership proof for it in the nullifier tree. This ensures that tags are incremental and cannot be skipped. -5. The precompile computes `new_tag = hash(alice, bob, secret, counter + 1)`, emits it as a nullifier, and prepends it to the note cyphertext before broadcasting it. +5. The precompile computes `new_tag = hash(alice, bob, secret, counter + 1)`, emits it as a nullifier, and prepends it to the note ciphertext before broadcasting it. ## Defined precompiles List of precompiles defined by the protocol: + | Address | Encryption | Note Tagging | Comments | -|---------|------------|--------------|----------| -| 0x01 | Noop | Noop | Used by accounts to explicitly signal that they cannot receive encrypted payloads. Validation method returns `true` only for an empty list of public keys. All other methods return empty. | -| 0x02 | AES128 | Trial decryption | | -| 0x03 | AES128 | Delegated trial decryption | | -| 0x04 | AES128 | Tag hopping | | +| ------- | ---------- | ------------ | -------- | +| 0x01 | Noop | Noop | Used by accounts to explicitly signal that they cannot receive encrypted payloads. Validation method returns `true` only for an empty list of public keys. All other methods return empty. | +| 0x02 | AES128 | Trial decryption | | +| 0x03 | AES128 | Delegated trial decryption | | +| 0x04 | AES128 | Tag hopping | | | diff --git a/yellow-paper/docs/bytecode/index.md b/yellow-paper/docs/bytecode/index.md index 6ebfd61e6e8..887acd29435 100644 --- a/yellow-paper/docs/bytecode/index.md +++ b/yellow-paper/docs/bytecode/index.md @@ -2,17 +2,32 @@ title: Bytecode --- + + This section describes how contracts are represented within the protocol for execution. In the context of Aztec, a contract is a set of functions which can be of one of three types: -- Private functions: The functions that run on user's machines. At the noir level, they are regular functions. +- Private functions: The functions that run on user's machines. At the noir level, they are regular programs. - Public functions: The functions that are run by sequencers. At the noir level, they are unconstrained functions, that are later proven by the public VM. -- Unconstrained functions: Helper functions that are run on user's machines but are not transacted to, meant to provide users with digested data about the contract's state. At the noir level, they are top level unconstrained functions. +- Unconstrained functions: Helper functions that are run on users' machines but are not constrained. At the noir level, they are top level unconstrained functions. + - Unconstrained functions are often used to fetch and serialize private data, for use as witnesses to a circuit. + - They can also be used to convey how dapps should handle a particular contract's data. When a contract is compiled, private and unconstrained functions are compiled individually. Public functions are compiled together to a single bytecode with an initial dispatch table based on function selectors. Since public functions are run in a VM, we do not incur a huge extra proving cost for the branching that is required to execute different functions. -There are three different (but related) bytecode standards that are used in Aztec, AVM bytecode, Brillig bytecode and ACIR bytecode. + + + +There are three different (but related) bytecode standards that are used in Aztec: AVM bytecode, Brillig bytecode and ACIR bytecode. # AVM Bytecode @@ -20,36 +35,38 @@ The AVM bytecode is the compilation target of the public functions of a contract # Brillig Bytecode -Brillig bytecode is the compilation target of all the unconstrained functions in noir. Any unconstrained function used by a private function is compiled to Brillig bytecode. Also, contract's top level unconstrained functions are entirely compiled to Brillig bytecode. +Brillig bytecode is the compilation target of all the unconstrained functions in noir. Any unconstrained function used by a private function is compiled to Brillig bytecode. Also, contracts' top level unconstrained functions are entirely compiled to Brillig bytecode. -Brillig bytecode will be a thin superset of AVM bytecode that allows for the use of oracles. Oracles allow nondeterminism during the execution of a given function, allowing the simulator entity to choose the value of a given oracle during the simulation process. Oracles are heavily used by aztec.nr to fetch data during simulation of private and unconstrained functions, such as fetching notes. They are also used to notify the simulator about events of the execution, such as a nullified note so it's not offered again in the simulation. Similarly to AVM bytecode, Brillig bytecode allows control flow. +Brillig bytecode will be a thin superset of AVM bytecode that allows for the use of oracles. Oracles allow nondeterminism during the execution of a given function, allowing the simulator entity to choose the value that an oracle will return during the simulation process. Oracles are heavily used by aztec.nr to fetch data during simulation of private and unconstrained functions, such as fetching notes. They are also used to notify the simulator about events arising during execution, such as a nullified note so that it's not offered again during the simulation. Similarly to AVM bytecode, Brillig bytecode allows control flow. The current implementation of Brillig can be found [in the noir repository](https://github.com/noir-lang/noir/blob/master/acvm-repo/brillig/src/opcodes.rs#L60). It'll change when the specification of AVM bytecode is finished to become a superset of it. # ACIR Bytecode -ACIR bytecode is the compilation target of all regular noir functions, including contract private functions. ACIR expresses arithmetic circuits and thus has no control flow. Control flow in regular functions is either unrolled (for loops) or flattened (by inlining and adding predicates), resulting in a single function with no control flow to be transformed to ACIR. +ACIR bytecode is the compilation target of all regular noir programs, including contract private functions. ACIR expresses arithmetic circuits and thus has no control flow. Control flow in regular functions is either unrolled (for loops) or flattened (by inlining and adding predicates), resulting in a single function with no control flow to be transformed to ACIR. The types of opcodes that can appear in ACIR are: - Arithmetic: They can express any degree-2 multivariate relation between witness indices. They are the most common opcodes in ACIR. - BlackBoxFuncCall: They assign the witnesses of the parameters and the witnesses of the return values of black box functions. Black box functions are commonly used operations that are treated as a black box, meaning that the underlying backend chooses how to prove them efficiently. -- Brillig: They assign the witnesses of the parameters and the witnesses of the return values of brillig functions. When an unconstrained function is called from a regular function, the bytecode for the called function gets embedded in a Brillig opcode. The simulator entity is the one responsible for executing the brillig bytecode. The results of the execution of the function are assigned to the witnesses of the return values and they should be constrained to be correct by the ACIR bytecode. +- Brillig: They assign the witnesses of the parameters and the witnesses of the return values of brillig functions. When an unconstrained function is called from a regular function, the bytecode for the called function gets embedded in a Brillig opcode . The simulator entity is the one responsible for executing the brillig bytecode. The results of the execution of the function are assigned to the witnesses of the return values and they should be constrained to be correct by the ACIR bytecode. - MemoryOp: They handle memory operations. When accessing arrays with indices unknown at compile time, the compiler cannot know which witness index is being read. The memory abstraction allows noir to read and write to dynamic positions in arrays in an efficient manner, offloading the responsibility of proving the correct access to the underlying backend. # Usage of the bytecode ### Compiling a contract + + When a contract is compiled, an artifact will be generated containing: - The private functions compiled to ACIR bytecode. The verification key of the private functions can be generated from the ACIR bytecode. - The unconstrained functions compiled to Brillig bytecode. - A public bytecode blob containing the bytecode of all the public functions compiled to AVM bytecode. -The public bytecode needs to be published to a data availability solution, since the sequencers need to have the data available to run the public functions. Also, it needs to use an encoding that is friendly to the public VM, such as the one specified in the [AVM section](../public-vm/bytecode-validation-circuit). +The public bytecode needs to be published to a data availability solution, since the sequencers need to have the data available to run the public functions. Also, it needs to use an encoding that is friendly to the public VM, such as the one specified in the [AVM section](../public-vm/bytecode-validation-circuit). -The bytecode of private and unconstrained functions doesn't need to be published, instead, users that desire to use a given contract can add the artifact to their PXE before interacting with it. Publishing it is convenient, but not required. However, the verification key of the private functions is tracked by the protocol, so the user can prove to the protocol that he executed the function correctly. +The bytecode of private and unconstrained functions doesn't need to be published, instead, users that desire to use a given contract can add the artifact to their PXE before interacting with it. Publishing it is convenient, but not required . However, the verification key of a private function is hashed into the function's leaf of the contract's function tree, so the user can prove to the protocol that he executed the function correctly. This implies that the encoding of private and unconstrained functions does not need to be friendly to circuits, since the only thing the protocol tracks is the verification key, allowing to use compression techniques. diff --git a/yellow-paper/docs/calls/batched-calls.md b/yellow-paper/docs/calls/batched-calls.md index 001f6819cd5..3da63823802 100644 --- a/yellow-paper/docs/calls/batched-calls.md +++ b/yellow-paper/docs/calls/batched-calls.md @@ -1,10 +1,18 @@ # Batched calls +:::warning +The low-level specifics of how batched calls will work is still being discussed. +::: + Calls to private functions can be _batched_ instead of executed [synchronously](./sync-calls.md). When executing a batched call to a private function, the function is not executed on the spot, but enqueued for execution at the end of local execution. Once the private call stack has been emptied, all batched execution requests are grouped by target (contract and function selector), and executed via a single call to each target. -Batched calls are implemented by pushing a `PrivateCallStackItem` with the flag `is_execution_request` into a `private_batched_queue` in the execution context, and require an oracle call to `batchPrivateFunctionCall` with the same arguments as other oracle function calls. + + +Batched calls are implemented by pushing a [`PrivateCallStackItem`](../circuits/private-kernel-initial.mdx#privatecallstackitem) with the flag `is_execution_request` into a `private_batched_queue` in the execution context, and require an oracle call to a `batchPrivateFunctionCall` function with the same argument types as for other oracle function calls. + +Batched calls are processed by the private kernel circuit. On each kernel circuit iteration, if the private call stack is not empty, the kernel circuit pops and processes the topmost entry. Otherwise, if the batched queue is not empty, the kernel pops the first item, collects and deletes all other items with the same target, and calls into the target. Note that this allows batched calls to trigger further synchronous calls. -Batched calls are processed by the private kernel circuit. On each kernel circuit iteration, if the private call stack is not empty, the kernel circuit pops and processes the topmost entry. Otherwise, if the batched queue is not empty, the kernel pops the first item, collects and deletes all other items with the same target, and calls into the target. Note that this allows batched calls to trigger synchronous calls. + The arguments for the batched call are arranged in an array with one position for each individual call. Each position within the array is a nested array where the first element is the call context for that individual call, followed by the actual arguments of the call. A batched call is expected to return an array of `PrivateCircuitPublicInputs`, where each public input's call context matches the call context from the corresponding individual call. This allows batched delegate calls, where each individual call processed has a context of its own. This can be used to emit logs on behalf of multiple contracts within a single batched call. @@ -24,4 +32,4 @@ loop: break ``` -The rationale for batched calls is to minimize the number of function calls in private execution, in order to reduce total proving times. Batched calls are mostly intended for usage with note delivery precompiles, since these do not require synchronous execution, and allows for processing all notes to be encrypted and tagged with the same mechanism using the same call. Batched calls can also be used for other common functions that do not require to be executed synchronously and are likely to be invoked multiple times. +The rationale for batched calls is to minimize the number of function calls in private execution, in order to reduce total proving times. Batched calls are mostly intended for usage with note delivery precompiles, since these do not require synchronous execution, and allows for processing all notes that are to be encrypted and tagged with the same mechanism using a single call. Batched calls can also be used for other common functions which do not require synchronous execution and which are likely to be invoked multiple times. diff --git a/yellow-paper/docs/calls/delegate-calls.md b/yellow-paper/docs/calls/delegate-calls.md index ccd0b7011a2..a9edd81b23e 100644 --- a/yellow-paper/docs/calls/delegate-calls.md +++ b/yellow-paper/docs/calls/delegate-calls.md @@ -1,7 +1,17 @@ # Delegate calls -Delegate calls are function calls against a contract class identifier instead of an instance. Any call, synchronous or asynchronous, can be made as a delegate call. The behavior of a delegate call is to execute the function code in the specified class identifier but on the context of the current instance. This opens the door to script-like executions and upgradeable contracts. Delegate calls are based on [EIP7](https://eips.ethereum.org/EIPS/eip-7). + + +Delegate calls are function calls against a contract class identifier instead of an instance. Any call -- synchronous or asynchronous -- can be made as a delegate call. The behavior of a delegate call is to execute the function code in the specified class identifier but in the context of the current instance. This opens the door to script-like executions and upgradeable contracts. Delegate calls are based on [EIP7](https://eips.ethereum.org/EIPS/eip-7). At the protocol level, a delegate call is identified by a `is_delegate_call` flag in the `CircuitPublicInputs` of the `CallStackItem`. The `contract_address` field is reinterpreted as a contract class instead. When executing a delegate call, the kernel preserves the values of the `CallContext` `msgSender` and `storageContractAddress`. + + At the contract level, a caller can initiate a delegate call via a `delegateCallPrivateFunction` or `delegateCallPublicFunction` oracle call. The caller is responsible for asserting that the returned `CallStackItem` has the `is_delegate_call` flag correctly set. diff --git a/yellow-paper/docs/calls/enqueued-calls.md b/yellow-paper/docs/calls/enqueued-calls.md index a654e021dfd..8b7cd09fe3d 100644 --- a/yellow-paper/docs/calls/enqueued-calls.md +++ b/yellow-paper/docs/calls/enqueued-calls.md @@ -1,7 +1,9 @@ # Enqueued calls -Calls from private functions to public functions are asynchronous. Since private and public functions are executed in different domains at different times and in different contexts, as the former are run by the user on a PXE and the latter by the sequencer, it is not possible for a private function to call a public one and await its result. Instead, private functions can _enqueue_ public function calls. + -The process is analogous to [synchronous calls](./sync-calls.md), but rely on an `enqueuePublicFunctionCall` oracle call that accepts the same arguments. The returned object by the enqueue call is a `PublicCallStackItem` with a flag `is_execution_request` set and empty side effects, to reflect that the stack item has not been executed yet. As with synchronous calls, the caller is responsible for validating the function and arguments in the call stack item, and to push its hash to its public call stack, which represents the list of enqueued public function calls. +Calls from private functions to public functions are asynchronous. Since private and public functions are executed in different domains at different times and in different contexts -- the former are run locally by the user in a PXE and the latter by the sequencer -- it is not possible for a private function to call a public one and await its result. Instead, private functions can _enqueue_ public function calls. -As the transaction is received by the sequencer, the public kernel circuit begins processing the enqueued public function calls from the transaction public call stack, pushing new recursive calls as needed, until the public call stack is empty, as described in the [synchronous calls](./sync-calls.md) section. +The process is analogous to [synchronous calls](./sync-calls.md), but relies on an `enqueuePublicFunctionCall` oracle call that accepts the same arguments. The object returned by the oracle is a `PublicCallStackItem` with a flag `is_execution_request` set, and empty side effects to reflect that the stack item has not been executed yet. As with synchronous calls, the caller is responsible for validating the function and arguments in the call stack item, and to push its hash to its public call stack, which represents the list of enqueued public function calls. + +Once the transaction is received by the sequencer, the public kernel circuit can begin processing the enqueued public function calls from the transaction's public call stack, pushing new recursive calls to the stack as needed, and popping-off one call stack item at a time, until the public call stack is empty, as described in the [synchronous calls](./sync-calls.md) section. diff --git a/yellow-paper/docs/calls/index.md b/yellow-paper/docs/calls/index.md index 5122c700f29..b19bfcbc5b3 100644 --- a/yellow-paper/docs/calls/index.md +++ b/yellow-paper/docs/calls/index.md @@ -2,9 +2,22 @@ title: Calls --- + + + + # Calls -Functions in the Aztec Network can call other functions. These calls are [synchronous](./sync-calls.md) when they they occur within private functions or within public functions, but are [enqueued](./enqueued-calls.md) when done from a private to a public function, and optionally [batched](./batched-calls.md). The protocol also supports alternate call methods, such as [static](./static-calls.md), [delegate](./delegate-calls.md), and [unconstrained](./unconstrained-calls.md) calls. +Functions in the Aztec Network can call other functions. There are several types of call: + +- [Synchronous calls](./sync-calls.md): when a private function calls another private function; or when a public function calls another public function. +- [Enqueued calls](./enqueued-calls.md): when a private function calls a public function. +- [Batched calls](./batched-calls.md): when multiple calls to the same function are enqueued and processed as a single call on a concatenation of the arguments. + +The protocol also supports alternative call methods, such as [static](./static-calls.md), [delegate](./delegate-calls.md), and [unconstrained](./unconstrained-calls.md) calls. In addition to function calls, the protocol allows for communication via message-passing back-and-forth between L1 and L2, as well as from public to private functions. diff --git a/yellow-paper/docs/calls/public-private-messaging.md b/yellow-paper/docs/calls/public-private-messaging.md index ddcff5a7b0e..b75cc6f622d 100644 --- a/yellow-paper/docs/calls/public-private-messaging.md +++ b/yellow-paper/docs/calls/public-private-messaging.md @@ -1,71 +1,83 @@ # Inter-Layer Calls + + ## Public-Private messaging -Public state and private state exist in different trees. In a private function you cannot reference or modify public state. +Public state and private state exist in different [trees](../state/index.md). In a private function you cannot reference or modify public state. + Yet, it should be possible for: 1. private functions to call private or public functions 2. public functions to call private or public functions -Private functions are executed locally by the user and work by providing evidence of correct execution generated locally through kernel proofs. This way, the sequencer doesn't need to have knowledge of everything happening in the transaction, only the results. Public functions, on the other hand, are able to utilize the latest state to manage updates and perform alterations, as they are executed by the sequencer. +Private functions are executed locally by the user, so that the user can ensure privacy of their data. Public functions are executed by the sequencer, who is the only party with an up-to-date view of the latest public state. It's natural, then, that private functions be executed first, and public functions be executed after the user has submitted a [transaction object](../transactions/tx-object.md) (which contains proof of private execution) to the network. Since a user doesn't have an up-to-date view of the latest state, private functions are always executed on some historical snapshot of the network's state. + +Given this natural flow from private-land to public-land, private functions can enqueue calls to public functions. But the opposite direction is not true. We'll see [below](#public-to-private-messaging) that public functions cannot "call" private functions, but rather they must pass messages. -Therefore, private functions are always executed first, as they are executed on a state $S_i$, where $i \le n$, with $S_n$ representing the current state where the public functions always operate on the current state $S_n$. +Since private functions execute first, they cannot 'wait' on the results of any of their calls to public functions. -This enables private functions to enqueue calls to public functions. But vice-versa is not true. Since private functions execute first, it cannot "wait" on the results of any of their calls to public functions. Stated differently, any calls made across domains are unilateral in nature. +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. -The figure below shows the order of function calls on the left-hand side, while the right-hand side shows how the functions will be executed. Notably, the second private function call is independent of the output of the public function and merely occurs after its execution. +```mermaid +graph LR + A[Private Function 1] --> |1st call| B(Public Function 1) + A --> |2nd call| C[Private Function 2] + C --> |return values| A + A --> |3rd call| D(Public Function 2) + A --> |4th call| E[Private Function 3] + E --> |return values| A +``` -Tx call order be: +The order of execution will actually be: ```mermaid -graph TD - A[Private Function 1] -->|Calls| B(Public Function 1) - A -----> |Followed by| C[Private Function 2] +graph LR + A[Private Function 1] --> C[Private Function 2] + C --> |return values| A + A[Private Function 1] --> E[Private Function 3] + E --> |return values| A + A -----> |Enqueued| B(Public Function 1) + A -----> |Enqueued| D(Public Function 2) ``` -But Tx execution order will be +And the order of proving will actually be: ```mermaid -graph TD - A[Private Function 1] -->|Calls| B(Private Function 2) - A -----> |Followed by| C[Public Function 1] +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 When a private function calls a public function: -1. Public function args get hashed together -1. A public call stack item is created with the public function selector, it's contract address and args hash -1. The hash of the item gets enqueued into a separate public call stack and passed as inputs to the private kernel -1. The private kernel pushes these hashes into the public input, which the sequencer can see. -1. PXE creates a transaction object as outlined [here](../transactions/tx-object.md) where it passes the hashes and the actual call stack item -1. PXE sends the transaction to the sequencer. -1. Sequencer then picks up the public call stack item and executes each of the functions. -1. The Public VM which executes the methods then verifies that the hash provided by the private kernel matches the current call stack item. +1. The arguments to the public function are hashed into an `args_hash`. +1. A `public_call_stack_item` is created, which includes the public function's `function_selector` , `contract_address`, and `args_hash`. +1. A hash of the `public_call_stack_item` gets enqueued into a separate [`public_call_stack`](../circuits/private-function.md#public-inputs) and passed as inputs to the private kernel. +1. The private kernel pushes these hashes onto its own the [`public_inputs`](../circuits/private-kernel-initial.mdx#public-inputs), which the sequencer can see. +1. The PXE creates a [`transaction_object`](../transactions/tx-object.md) which includes the kernel's `public_inputs`. +1. The PXE sends the `transaction_object` to the sequencer. +1. Sequencer then unpacks the `public_call_stack_item` and executes each of the functions. +1. The Public VM executes the enqueued public calls, and then verifies that the hash provided by the private kernel matches the current call stack item. ### Handling Privacy Leakage and `msg.sender` -In the above design, the sequencer only sees the public part of the call stack along with any new commitments, nullifiers etc that were created in the private transaction i.e. should learns nothing more of the private transaction (such as its origin, execution logic etc). - -:::warning -TODO: Haven't finalized what msg.sender will be -::: +The sequencer only sees the data in the [`transaction_object`](../transactions/tx-object.md), which shouldn't expose any private information. There are some [practical caveats](http://docs.aztec.network). -Within the context of these enqueued public functions, any usage of `msg_sender` should return **TODO**. If the `msg_sender` is the actual user, then it leaks privacy. If `msg_sender` is the contract address, this leaks which contract is calling the public method and therefore leaks which contract the user was interacting with in private land. +When making a private-to-public call, the `msg_sender` will become public. If this is the actual user, then it leaks privacy. If `msg_sender` is some application's contract address, this leaks which contract is calling the public method and therefore leaks which contract the user was interacting with in private land. -Therefore, when the call stack is passed to the kernel circuit, the kernel should assert the `msg_sender` is 0 and hash appropriately. +An out-of-protocol option to randomizing `msg.sender` (as a user) would be to deploy a [diversified account contract](../addresses-and-keys/diversified-and-stealth.md) and route transactions through this contract. Application developers might also be able to do something similar, to randomize the `msg.sender` of their app contract's address. ### Reverts -If the private part of the transaction reverts, then public calls are never enqueued. But if the public part of the transaction reverts, it should still revert the entire transaction i.e. the sequencer should drop the execution results of the private part of the transaction and not include those in the state transitioner smart contract. However, since the sequencer had to execute your transaction, appropriate fee will be charged. Reverting in public causing the whole transaction to be dropped enables existing paradigms of ethereum where your valid transaction can revert because of altered state e.g., trade incurring too much slippage. +If the private part of a transaction reverts, then public calls are never enqueued. But if the public part of the transaction reverts, it should still revert the entire transaction. I.e. the sequencer should drop the execution results of the private part of the transaction and not include those in the state transitioner smart contract. A fee can still be charged by the sequencer for their compute effort. ## Public to Private Messaging -Since public functions execute after private functions, it isn't possible for public to call a private function in the same transaction. Nevertheless, it is quite useful for public functions to have a message passing system to private. A public function could add messages to an append only merkle tree to save messages from a public function call, that can later be executed by a private function. Note, only a transaction coming after the one including the message from a public function can consume it. In practice this means that unless you are the sequencer it will not be within the same rollup. +Since public functions execute after private functions, it isn't possible for a public function to call a private function in the same transaction. Nevertheless, it is quite useful for public functions to have a message passing system to private land. A public function can add messages to the [Note Hash Tree](../state/note-hash-tree.md) to save messages from a public function call, that can later be consumed by a private function. Note: such a message can only be consumed by a _later_ transaction. In practice this means that unless you are the sequencer (or have an out of protocol agreement with the sequencer) it cannot be consumed within the same rollup. -To elaborate, a public function may not have read access to encrypted private state in the note hash tree, but it can write to it. You could create a note in the public domain, compute it's note hash which gets passed to the inputs of the public VM which adds the hash to the note hash tree. The user who wants to redeem the note can add the note preimage to their PXE and then redeem/nullify the note in the private domain at a later time. +To elaborate, a public function may not have read access to encrypted private state in the Note Hash Tree, but it can write to it. You could create a note in the public domain, compute its note hash which gets passed to the inputs of the public VM which adds the hash to the note hash tree. The user who wants to redeem the note can add the note preimage to their PXE and then redeem/nullify the note in the private domain at a later time. In the picture below, it is worth noting that all data reads performed by private functions are historical in nature, and that private functions are not capable of modifying public storage. Conversely, public functions have the capacity to manipulate private storage (e.g., inserting new commitments, potentially as part of transferring funds from the public domain to the private domain). diff --git a/yellow-paper/docs/calls/static-calls.md b/yellow-paper/docs/calls/static-calls.md index 2462d95639a..61756cfb413 100644 --- a/yellow-paper/docs/calls/static-calls.md +++ b/yellow-paper/docs/calls/static-calls.md @@ -4,6 +4,15 @@ In particular, the following fields of the returned `CallStackItem` must be zero or empty in a static call: + + + - `new_commitments` - `new_nullifiers` - `nullified_commitments` diff --git a/yellow-paper/docs/calls/sync-calls.md b/yellow-paper/docs/calls/sync-calls.md index 8b3b8941c6d..b760716eb92 100644 --- a/yellow-paper/docs/calls/sync-calls.md +++ b/yellow-paper/docs/calls/sync-calls.md @@ -1,16 +1,20 @@ # Synchronous calls + + Calls from a private function to another private function, as well as calls from a public function to another public function, are _synchronous_. When a synchronous function call is found during execution, execution jumps to the target of the call, and returns to the caller with a return value from the function called. This allows easy composability across contracts. -At the protocol level, each call is represented as a `CallStackItem`, which includes the contract address and function being called, as well as the public inputs `PrivateCircuitPublicInputs` or `PublicCircuitPublicInputs` that are outputted by the execution of the called function. These public inputs include information on the call context, the side effects of the execution, and the block header. +At the protocol level, each call is represented as a [`CallStackItem`](../circuits/private-kernel-initial.mdx#privatecallstackitem), which includes the contract address and function being called, as well as the public inputs [`PrivateCircuitPublicInputs`](../circuits/private-function.md#public-inputs) or `PublicCircuitPublicInputs` that are outputted by the execution of the called function. These public inputs include information on the call context, the side effects of the execution, and the block header. At the contract level, a call is executed via an oracle call `callPrivateFunction` or `callPublicFunction`, both of which accept the contract address to call, the function selector, and a hash of the arguments. The oracle call prompts the executor to pause the current frame, jump to the target of the call, and return its result. The result is a `CallStackItem` that represents the nested execution. -The caller is responsible for asserting that the function and arguments in the returned `CallStackItem` match the requested ones, otherwise a malicious oracle could return a `CallStackItem` for a different execution. The caller must also push the hash of the returned `CallStackItem` into the private or public call stack of the current execution context, which is returned as part of the `CircuitPublicInputs` output. The end result is a top-level entrypoint `CallStackItem`, with a stack of nested call stack items to process. +The calling function is responsible for asserting that the function and arguments in the returned `CallStackItem` match the requested ones, otherwise a malicious oracle could return a `CallStackItem` for a different execution. The calling function must also push the hash of the returned `CallStackItem` into the private or public call stack of the current execution context, which is returned as part of the circuit's [PublicInputs](../circuits/private-function.md#public-inputs) output. The end result is a top-level entrypoint `CallStackItem`, which itself contains (nested within) a stack of call stack items to process. + +The kernel circuit is then responsible for iteratively processing each `CallStackItem`, pushing new items into the stack as it encounters nested calls, and popping one item off the stack with each kernel iteration until the stack is empty. The private kernel circuit processes private function calls locally in the PXE, whereas the public kernel circuit processes public function calls on the sequencer's machine. -The kernel circuit is then responsible for iteratively processing each `CallStackItem`, pushing new items into the stack as it encounters nested calls, until the stack is empty. The private kernel circuit processes private function calls locally in the PXE, whereas the public kernel circuit processes public function calls on the sequencer. +The private kernel circuit iterations begin with the entrypoint execution, empty output and proof. The public kernel circuit starts with the public call stack in the transaction object , and builds on top of the output and proof of the private kernel circuit. -The private kernel circuit iterations begin with the entrypoint execution, empty output and proof. The public kernel circuit starts with the public call stack in the transaction object, and builds on top of the output and proof of the private kernel circuit. + ``` let call_stack, kernel_public_inputs, proof @@ -30,3 +34,5 @@ while call_stack is not empty: ``` The kernel circuit asserts that nested functions and their side effects are processed in order, and that the hash of each nested execution matches the corresponding hash outputted in the call stack by each `CircuitPublicInputs`. + +For more information about how the private kernel circuit works, see [here](../circuits/private-kernel-initial.mdx). diff --git a/yellow-paper/docs/calls/unconstrained-calls.md b/yellow-paper/docs/calls/unconstrained-calls.md index 9a90061cc4a..9fe11f46600 100644 --- a/yellow-paper/docs/calls/unconstrained-calls.md +++ b/yellow-paper/docs/calls/unconstrained-calls.md @@ -1,11 +1,15 @@ # Unconstrained calls - + + Private function calls can be executed as _unconstrained_. Unconstrained function calls execute the code at the target and return the result, but their execution is not constrained. It is responsibility of the caller to constrain the result, if needed. Unconstrained calls are a generalization of oracle function calls, where the call is not to a PXE function but to another contract. Side effects from unconstrained calls are ignored. Note that all calls executed from an unconstrained call frame will be unconstrained as well. Unconstrained calls are executed via a `unconstrainedCallPrivateFunction` oracle call, which accepts the same arguments as a regular `callPrivateFunction`, and return the result from the function call. Unconstrained calls are not pushed into the `private_call_stack` and do not incur in an additional kernel iteration. -Rationale for unconstrained calls is to allows apps to consume results from functions that do not need to be provable. An example use case for unconstrained calls is unconstrained encryption and note tagging, which can be used when the sender is incentivized to ensure the recipient receives the data sent. +THe rationale for unconstrained calls is to allows apps to consume results from functions that do not need to be provable. An example use case for unconstrained calls is unconstrained encryption and note tagging, which can be used in applications where constraining such encryption computations isn't necessary, e.g. if the sender is incentivized to ensure the recipient receives the correct data. Another motivation for unconstrained calls is for retrieving or computing data where the end result can be more efficiently constrained by the caller. diff --git a/yellow-paper/docs/circuits/high-level-topology.md b/yellow-paper/docs/circuits/high-level-topology.md index dd6263760f2..a25e9b5007d 100644 --- a/yellow-paper/docs/circuits/high-level-topology.md +++ b/yellow-paper/docs/circuits/high-level-topology.md @@ -4,10 +4,17 @@ A transaction begins with a call to a private function, which may invoke nested calls to other private and public functions. The entire set of private function calls is executed in a secure environment, and their proofs are validated and aggregated by private kernel circuits. Meanwhile, any public function calls triggered from private functions will be enqueued. The proofs for these calls, along with those from the nested public function calls, are generated and processed through public kernel circuits in any entity possessing the correct contexts. -Once all functions in a transaction are executed, the accumulated data is outputted from a tail circuit. These values are then inserted or updated to the trees within the base rollup circuit. The merge rollup circuit facilitates the merging of two rollup proofs. Repeating this merging process enables the inclusion of more transactions in a block. Finally, the root rollup circuit produces the final proof, which is subsequently submitted and validated onchain. +Once all functions in a transaction are executed, the accumulated data is outputted from a tail circuit. These values are then inserted or updated to the [state trees](../state/index.md) within the base rollup circuit. The merge rollup circuit facilitates the merging of two rollup proofs. Repeating this merging process enables the inclusion of more transactions in a block. Finally, the root rollup circuit produces the final proof, which is subsequently submitted and validated onchain. To illustrate, consider a transaction involving the following functions, where circles depict private functions, and squares denote public functions: +:::info +A note for Aztec protocol developers: In this yellow paper, the order in which the kernel circuit processes calls is different from previous literature, and is different from the current implementation (as at January 2024). +::: + + + ```mermaid flowchart LR f0([f0]) --> f1([f1]) @@ -123,8 +130,8 @@ flowchart TB A few things to note: -- A transaction always starts with an [initial private kernel circuit](./private-kernel-initial.md). -- An [inner private kernel circuit](./private-kernel-inner.md) won't be required if there is only one private function in a transaction. +- A transaction always starts with an [initial private kernel circuit](./private-kernel-initial.mdx). +- An [inner private kernel circuit](./private-kernel-inner.mdx) won't be required if there is only one private function in a transaction. - A [reset private kernel circuit](./private-kernel-reset.md) can be executed between two private kernel circuits to "reset" transient data. The reset process can be repeated as needed. - Public functions are "enqueued" when invoked from a private function. Public kernel circuits will be executed after the completion of all private kernel iterations. - A [base rollup circuit](../rollup-circuits/base-rollup.md) can accept either a [tail public kernel circuit](./public-kernel-tail.md), or a [tail private kernel circuit](./private-kernel-tail.md) in cases where no public functions are present in the transaction. diff --git a/yellow-paper/docs/circuits/private-function.md b/yellow-paper/docs/circuits/private-function.md index 8418056b83a..7f843a23d21 100644 --- a/yellow-paper/docs/circuits/private-function.md +++ b/yellow-paper/docs/circuits/private-function.md @@ -2,9 +2,9 @@ ## Requirements -Private function circuits represent smart contract functions that modify the Aztec private state trees. They serve as untrusted, third-party code that is executed as part of evaluating an Aztec transaction. +Private function circuits represent smart contract functions that can: privately read and modify leaves of the note hash tree and nullifier tree; perform computations on private data; and can be executed without revealing which function or contract has been executed. -The logic of each private function circuit is tailored to the needs of a particular application or scenario, yet its public inputs must adhere to a specific format. This circuit should be designed to handle private data processing while generating public inputs that safeguard the application and account's intentions without compromising sensitive information. +The logic of each private function circuit is tailored to the needs of a particular application or scenario, but the public inputs of every private function circuit _must_ adhere to a specific format. This specific format (often referred to as the "public inputs ABI for private functions") ensures that the [private kernel circuits](./private-kernel-initial.mdx) can correctly interpret the actions of every private function circuit. ## Private Inputs @@ -12,105 +12,137 @@ The private inputs of a private function circuit are customizable. ## Public Inputs -The public inputs of a private function circuit will be incorporated into the private inputs of a private kernel circuit. Private kernel circuits leverage these public inputs, coupled with proof data and verification key from a private function circuit, to prove the correct execution of a private function. - -The following format defines the ABI that is used by the private kernel circuit when processing private function public inputs: - -| Field | Type | Description | -| ----------------------------------- | ------------------------------------------------------------------------ | --------------------------------------------------------------------- | -| _call_context_ | _[CallContext](#callcontext)_ | Context of the call corresponding to this function execution. | -| _args_hash_ | _field_ | Hash of the function arguments. | -| _return_values_ | [_field_; _C_] | Return values of this function call. | -| _read_requests_ | [_[ReadRequest](#readrequest)_; _C_] | Requests to read notes in the note hash tree. | -| _nullifier_key_validation_requests_ | [_[NullifierKeyValidationRequest](#nullifierkeyvalidationrequest)_; _C_] | Requests to validate nullifier keys used in this function call. | -| _note_hashes_ | [_[NoteHash](#notehash)_; _C_] | New note hashes created in this function call. | -| _nullifiers_ | [_[Nullifier](#nullifier)_; _C_] | New nullifiers created in this function call. | -| _l2_to_l1_messages_ | [_field_; _C_] | New L2 to L1 messages created in this function call. | -| _unencrypted_log_hashes_ | [_[UnencryptedLogHash](#unencryptedloghash)_; _C_] | Hashes of the unencrypted logs emitted in this function call. | -| _encrypted_log_hashes_ | [_[EncryptedLogHash](#encryptedloghash)_; _C_] | Hashes of the encrypted logs emitted in this function call. | -| _encrypted_note_preimage_hashes_ | [_[EncryptedNotePreimageHash](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages emitted in this function call. | -| _private_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the private function calls initiated by this function. | -| _public_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the public function calls initiated by this function. | -| _header_ | _[Header](#header)_ | Header of a block which was used when assembling the tx. | -| _chain_id_ | _field_ | Chain ID of the transaction. | -| _version_ | _field_ | Version of the transaction. | - -> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. + + + + +The public inputs of _every_ private function _must_ adhere to the following ABI: + +| Field | Type | Description | +| ----------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `call_context` | [`CallContext`](#callcontext) | Context of the call corresponding to this function execution. | +| `args_hash` | `field` | Hash of the function arguments. | +| `return_values` | `[field; C]` | Return values of this function call. | +| `read_requests` | [`[ReadRequest; C]`](#readrequest) | Requests to read notes in the note hash tree. | +| `nullifier_key_validation_requests` | [`[NullifierKeyValidationRequest]; C]`](#nullifierkeyvalidationrequest) | Requests to validate nullifier keys used in this function call. | +| `note_hashes` | [`[NoteHash; C]`](#notehash) | New note hashes created in this function call. | +| `nullifiers` | [`[Nullifier; C]`](#nullifier) | New nullifiers created in this function call. | +| `l2_to_l1_messages` | `[field; C]` | New L2 to L1 messages created in this function call. | +| `unencrypted_log_hashes` | [`[UnencryptedLogHash; C]`](#unencryptedloghash) | Hashes of the unencrypted logs emitted in this function call. | +| `encrypted_log_hashes` | [`[EncryptedLogHash; C]`](#encryptedloghash) | Hashes of the encrypted logs emitted in this function call. | +| `encrypted_note_preimage_hashes` | [`[EncryptedNotePreimageHash]; C]`](#encryptednotepreimagehash) | Hashes of the encrypted note preimages emitted in this function call. | +| `private_call_stack_item_hashes` | `[field; C]` | Hashes of the private function calls initiated by this function. | +| `public_call_stack_item_hashes` | `[field; C]` | Hashes of the public function calls initiated by this function. | +| `block_header` | [`BlockHeader`](#blockheader) | Information about the trees used for the transaction. | +| `chain_id` | `field` | Chain ID of the transaction. | +| `version` | `field` | Version of the transaction. | + +After generating a proof for a private function circuit, that proof (and associated public inputs) will be passed-into a private kernel circuit as private inputs. Private kernel circuits use the private function's proof, public inputs, and verification key, to verify the correct execution of the private function. Private kernel circuits then perform a number of checks and computations on the private function's public inputs. + +> The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. + + ## Types -#### _CallContext_ +### `CallContext` -| Field | Type | Description | -| -------------------------- | -------------- | ----------------------------------------------------------------------- | -| _msg_sender_ | _AztecAddress_ | Address of the caller contract. | -| _storage_contract_address_ | _AztecAddress_ | Address of the contract against which all state changes will be stored. | -| _portal_contract_address_ | _AztecAddress_ | Address of the portal contract to the storage contract. | -| _is_delegate_call_ | _bool_ | A flag indicating whether the call is a delegate call. | -| _is_static_call_ | _bool_ | A flag indicating whether the call is a static call. | +| Field | Type | Description | +| -------------------------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `msg_sender` | `AztecAddress` | Address of the caller contract. | +| `storage_contract_address` | `AztecAddress` | Address of the contract against which all state changes will be stored. (It is not called `contract_address`, because in the context of delegate calls, that would be an ambiguous name.) | +| `portal_contract_address` | `AztecAddress` | Address of the portal contract to the storage contract. | +| `is_delegate_call` | `bool` | A flag indicating whether the call is a [delegate call](../calls/delegate-calls.md). | +| `is_static_call` | `bool` | A flag indicating whether the call is a [static call](../calls/static-calls.md). | -#### _ReadRequest_ +### `ReadRequest` | Field | Type | Description | | ----------- | ------- | -------------------------------------- | -| _note_hash_ | _field_ | Hash of the note to be read. | -| _counter_ | _field_ | Counter at which the request was made. | +| `note_hash` | `field` | Hash of the note to be read. | +| `counter` | `field` | Counter at which the request was made. | -#### _NullifierKeyValidationRequest_ +### `NullifierKeyValidationRequest` + + | Field | Type | Description | | ------------ | ------- | -------------------------------------------------------------------- | -| _public_key_ | _field_ | Nullifier public key of an account. | -| _secret_key_ | _field_ | Nullifier secret key of an account siloed with the contract address. | +| `public_key` | `field` | Nullifier public key of an account. | +| `secret_key` | `field` | Nullifier secret key of an account siloed with the contract address. | -#### _NoteHash_ +### `NoteHash` | Field | Type | Description | | --------- | ------- | ------------------------------------------- | -| _value_ | _field_ | Hash of the note. | -| _counter_ | _field_ | Counter at which the note hash was created. | +| `value` | `field` | Hash of the note. | +| `counter` | `field` | Counter at which the note hash was created. | -#### _Nullifier_ +### `Nullifier` | Field | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | -| _value_ | _field_ | Value of the nullifier. | -| _counter_ | _field_ | Counter at which the nullifier was created. | -| _note_hash_counter_ | _field_ | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | +| `value` | `field` | Value of the nullifier. | +| `counter` | `field` | Counter at which the nullifier was created. | +| `note_hash_counter` | `field` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | + +### `UnencryptedLogHash` -#### _UnencryptedLogHash_ + | Field | Type | Description | | --------- | ------- | -------------------------------------- | -| _hash_ | _field_ | Hash of the unencrypted log. | -| _length_ | _field_ | Number of fields of the log preimage. | -| _counter_ | _field_ | Counter at which the hash was emitted. | +| `hash` | `field` | Hash of the unencrypted log. | +| `length` | `field` | Number of fields of the log preimage. | +| `counter` | `field` | Counter at which the hash was emitted. | -#### _EncryptedLogHash_ +### `EncryptedLogHash` | Field | Type | Description | | ------------ | ------- | -------------------------------------------- | -| _hash_ | _field_ | Hash of the encrypted log. | -| _length_ | _field_ | Number of fields of the log preimage. | -| _randomness_ | _field_ | A random value to hide the contract address. | -| _counter_ | _field_ | Counter at which the hash was emitted. | +| `hash` | `field` | Hash of the encrypted log. | +| `length` | `field` | Number of fields of the log preimage. | +| `counter` | `field` | Counter at which the hash was emitted. | +| `randomness` | `field` | A random value to hide the contract address. | -#### _EncryptedNotePreimageHash_ +### `EncryptedNotePreimageHash` | Field | Type | Description | | ------------------- | ------- | --------------------------------------- | -| _hash_ | _field_ | Hash of the encrypted note preimage. | -| _length_ | _field_ | Number of fields of the note preimage. | -| _counter_ | _field_ | Counter at which the hash was emitted. | -| _note_hash_counter_ | _field_ | Counter of the corresponding note hash. | +| `hash` | `field` | Hash of the encrypted note preimage. | +| `length` | `field` | Number of fields of the note preimage. | +| `counter` | `field` | Counter at which the hash was emitted. | +| `note_hash_counter` | `field` | Counter of the corresponding note hash. | -#### _Header_ +### `BlockHeader` | Field | Type | Description | | ----------------------------- | ------- | ----------------------------------------------------------------------------------------------- | -| _note_hash_tree_root_ | _field_ | Root of the note hash tree. | -| _nullifier_tree_root_ | _field_ | Root of the nullifier tree. | -| _l1_to_l2_messages_tree_root_ | _field_ | Root of the l1-to-l2 messages tree. | -| _public_data_tree_root_ | _field_ | Root of the public data tree. | -| _archive_tree_root_ | _field_ | Root of the state roots tree archived at the block prior to when the transaction was assembled. | -| _global_variables_hash_ | _field_ | Hash of the previous global variables. | +| `note_hash_tree_root` | `field` | Root of the note hash tree. | +| `nullifier_tree_root` | `field` | Root of the nullifier tree. | +| `l1_to_l2_messages_tree_root` | `field` | Root of the l1-to-l2 messages tree. | +| `public_data_tree_root` | `field` | Root of the public data tree. | +| `archive_tree_root` | `field` | Root of the state roots tree archived at the block prior to when the transaction was assembled. | +| `global_variables_hash` | `field` | Hash of the previous global variables. | diff --git a/yellow-paper/docs/circuits/private-kernel-initial.md b/yellow-paper/docs/circuits/private-kernel-initial.md deleted file mode 100644 index ba3e64733a8..00000000000 --- a/yellow-paper/docs/circuits/private-kernel-initial.md +++ /dev/null @@ -1,407 +0,0 @@ -# Private Kernel Circuit - Initial - -## Requirements - -In the **initial** kernel iteration, the process involves taking a transaction request and private call data, verifying their integrity, and preparing the necessary data for subsequent circuits to operate. This step is particularly beneficial due to its separation from the [inner private kernel circuit](./private-kernel-inner.md), as the first call lacks a "previous kernel" to process. Additionally, it executes tasks that are pertinent to a transaction and need only occur once. - -### Key Responsibilities Specific to this Circuit - -#### Validating the correspondence of function call with caller's intent. - -This entails ensuring that the following from the _[private_call](#privatecall)_ aligns with the specifications in the _[transaction_request](#transactionrequest)_: - -- _contract_address_ -- _function_data_ -- _args_hash_: Hash of the function arguments. - -> Although it's not enforced in the protocol, it is customary to provide a signature signed over the transaction request and verify it in the first function call. This practice guarantees that only the party possessing the key(s) can authorize a transaction with the exact transaction request on behalf of an account. - -#### Verifying the legitimacy of the function as the entrypoint. - -For the _[function_data](#functiondata)_ in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem)_, the circuit verifies that: - -- It must be a private function: - - _`function_data.function_type == private`_ -- It must not be an internal function: - - _`function_data.is_internal == false`_ - -#### Ensuring the function call is the first call. - -For the _[call_context](./private-function.md#callcontext)_ in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs)_, the circuit checks that: - -- It must not be a delegate call: - - _`call_context.is_delegate_call == false`_ -- It must not be a static call: - - _`call_context.is_static_call == false`_ - -#### Ensuring transaction uniqueness. - -It must emit the hash of the _[transaction_request](#transactionrequest)_ as the **first** nullifier. - -The hash is computed as: - -_`hash(origin, function_data.hash(), args_hash, tx_context.hash())`_ - -Where _function_data.hash()_ and _tx_context.hash()_ are the hashes of the serialized field elements. - -This nullifier serves multiple purposes: - -- Identifying a transaction. -- Non-malleability. Preventing the signature of a transaction request from being reused in another transaction. -- Generating values that should be maintained within the transaction's scope. For example, it is utilized to [compute the nonces](./private-kernel-tail.md#siloing-values) for all the note hashes in a transaction. - -> Note that the final transaction data is not deterministic for a given transaction request. The production of new notes, the destruction of notes, and various other values are likely to change based on the time and conditions when a transaction is being composed. However, the intricacies of implementation should not be a concern for the entity initiating the transaction. - -### Processing Private Function Call - -#### Ensuring the function being called exists in the contract. - -With the following data provided from _[private_inputs](#private-inputs).[private_call](#privatecall)_: - -- _contract_address_ in _private_call.[call_stack_item](#privatecallstackitem)_. -- _contract_data_ -- _contract_class_data_ -- _function_data_ in _private_call.[call_stack_item](#privatecallstackitem)_. - -This circuit validates the existence of the function in the contract through the following checks: - -1. Verify that the _contract_address_ can be derived from the _contract_data_: - - Refer to the details [here](../contract-deployment/instances.md#address) for the process of computing the address for a contract instance. - -2. Verify that the _contract_data.contract_class_id_ can be derived from the given _contract_class_data_: - - Refer to the details [here](../contract-deployment/classes.md#class-identifier) for the process of computing the _contract_class_id_. - -3. Verify that _contract_class_data.private_functions_ includes the function being called: - - 1. Compute the hash of the verification key: - - _`vk_hash = hash(private_call.vk)`_ - 2. Compute the function leaf: - - _`hash(function_data.selector, vk_hash, private_call.bytecode_hash)`_ - 3. Perform a membership check on the function leaf, where: - - The index and sibling path are provided through _function_leaf_membership_witness_ within _[private_call](#privatecall)_. - - The root is _contract_class_data.private_functions_. - -#### Verifying the private function proof. - -It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs of the [private function circuit](./private-function.md). - -#### Verifying the public inputs of the private function circuit. - -It ensures the private function circuit's intention by checking the following in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs)_: - -- The _header_ must match the one in the _[constant_data](#constantdata)_. - -#### Verifying the counters. - -It verifies that each value listed below is associated with a legitimate counter. - -1. For the _[call_stack_item](#privatecallstackitem)_: - - - The _counter_start_ must be 0. - - This check can be skipped for [inner private kernel circuit](./private-kernel-inner.md#verifying-the-counters). - - The _counter_end_ must be greater than the _counter_start_. - -2. For items in each ordered array in _[call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs)_: - - - The _counter_ of the first item must be greater than the _counter_start_ of the _call_stack_item_. - - The _counter_ of each subsequent item must be greater than the _counter_ of the previous item. - - The _counter_ of the last item must be less than the _counter_end_ of the _call_stack_item_. - - The ordered arrays include: - - - _note_hashes_ - - _nullifiers_ - - _read_requests_ - - _unencrypted_log_hashes_ - - _encrypted_log_hashes_ - - _encrypted_note_preimage_hashes_ - -3. For the last _N_ non-empty items in the _private_call_requests_ in the _[transient_accumulated_data](#transientaccumulateddata)_: - - - The _counter_end_ of each request must be greater than its _counter_start_. - - The _counter_end_ of the first request must be less than the _counter_end_ of the _call_stack_item_. - - The _counter_end_ of the second and subsequent requests must be less than the _counter_start_ of the previous request. - - The _counter_start_ of the last request must be greater than the _counter_start_ of the _call_stack_item_. - - > _N_ is the number of non-zero hashes in the _private_call_stack_item_hashes_ in _[private_inputs](#private-inputs).[private_call](#privatecall).[public_inputs](./private-function.md#public-inputs)_. - -4. For the last _N_ non-empty items in the _public_call_requests_ in the _[transient_accumulated_data](#transientaccumulateddata)_: - - - The _counter_start_ of the first request must be greater than the _counter_start_ of the _call_stack_item_. - - The _counter_start_ of each subsequent request must be greater than the _counter_start_ of the previous item. - - The _counter_start_ of the last item must be less than the _counter_end_ of the _call_stack_item_. - - > _N_ is the number of non-zero hashes in the _public_call_stack_item_hashes_ in _[private_inputs](#private-inputs).[private_call](#privatecall).[public_inputs](./private-function.md#public-inputs)_. - - > Note that the _counter_end_ of public call request is unknown at this point. Both counters will be [recalibrated](./public-kernel-initial.md#recalibrating-counters) in the initial public kernel circuit following the simulation of all public function calls. - -> Note that, for the initial private kernel circuit, all values within the _[transient_accumulated_data](#transientaccumulateddata)_ originate from the _[private_call](#privatecall)_. However, this process of counter verification is also applicable to the [inner private kernel circuit](./private-kernel-inner.md#verifying-the-counters), where the _transient_accumulated_data_ comprises values from previous iterations and the current function call. Therefor, only the last _N_ items need to be checked in the above operations. - -### Validating Public Inputs - -#### Verifying the transient accumulated data. - -Within the _[public_inputs](#public-inputs)_, the _[transient_accumulated_data](#transientaccumulateddata)_ encapsulates values reflecting the operations conducted by the _private_call_. - -This circuit verifies that the values in _[private_inputs](#private-inputs).[private_call](#privatecall).[call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs)_ (_private_function_public_inputs_) are aggregated into the _public_inputs_ correctly: - -1. Ensure that the specified values in the following arrays match those in the corresponding arrays in the _private_function_public_inputs_: - - - _note_hash_contexts_ - - _value_, _counter_ - - _nullifier_contexts_ - - _value_, _counter_ - - _l2_to_l1_message_contexts_ - - _value_ - - _read_request_contexts_ - - _note_hash_, _counter_ - - _public_call_requests_ - - _hash_, _counter_ - - _unencrypted_log_hash_contexts_ - - _hash_, _length_, _counter_ - - _encrypted_log_hash_contexts_ - - _hash_, _length_, _randomness_, _counter_ - - _encrypted_note_preimage_hash_contexts_ - - _hash_, _length_, _counter_, _note_hash_counter_ - -2. Check that the hashes in the _private_call_requests_ align with the values in the _private_call_stack_item_hashes_ in the _private_function_public_inputs_, but in **reverse** order. - - > It's important that the call requests are arranged in reverse order to ensure they are executed in chronological order. - -3. For each non-empty call request in both _private_call_requests_ and _public_call_requests_: - - - The _caller_contract_address_ equals the _contract_address_ in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem)_. - - The following values in _caller_context_ are either empty or align with the values in the _call_context_ within _private_function_public_inputs_: - - _`(caller_context.msg_sender == 0) & (caller_context.storage_contract_address == 0)`_ - - Or _`(caller_context.msg_sender == call_context.msg_sender) & (caller_context.storage_contract_address == call_context.storage_contract_address)`_ - - The _is_static_call_ flag must be propagated: - - _`caller_context.is_static_call == call_context.is_static_call`_ - - > The caller context in a call request may be empty for standard calls. This precaution is crucial to prevent information leakage, particularly as revealing the _msg_sender_ of this private function when calling a public function could pose security risks. - -4. For each non-empty item in the following arrays, its _contract_address_ must equal the _storage_contract_address_ defined in _private_function_public_inputs.call_context_: - - - _note_hash_contexts_ - - _nullifier_contexts_ - - _l2_to_l1_message_contexts_ - - _read_request_contexts_ - - _nullifier_key_validation_request_contexts_ - - _unencrypted_log_hash_contexts_ - - _encrypted_log_hash_contexts_ - - _encrypted_note_preimage_hash_contexts_ - - > Ensuring the alignment of the contract addresses is crucial, as it is later used to [silo the values](./private-kernel-tail.md#siloing-values) and to establish associations with values within the same contract. - -5. For each non-empty item in _l2_to_l1_message_contexts_, its _portal_contract_address_ must equal the _portal_contract_address_ defined in _private_function_public_inputs.call_context_. - -6. For each _note_hash_ in the _note_hash_contexts_, verify that it is associated with a _nullifier_counter_. The value of the _nullifier_counter_ can be: - - - Zero: if the note is not nullified in the same transaction. - - Greater than _note_hash.counter_: if the note is nullified in the same transaction. - - > Nullifier counters are used in the [reset private kernel circuit](./private-kernel-reset.md#read-request-reset-private-kernel-circuit) to ensure a read happens **before** a transient note is nullified. - - > Zero can be used to indicate a non-existing transient nullifier, as this value can never serve as the counter of a nullifier. It corresponds to the _counter_start_ of the first function call. - -> Note that the verification process outlined above is also applicable to the inner private kernel circuit. However, given that the _transient_accumulated_data_ for the inner private kernel circuit comprises both values from previous iterations and the _private_call_, the above process specifically targets the values stemming from the _private_call_. The inner kernel circuit performs an [extra check](./private-kernel-inner.md#verifying-the-transient-accumulated-data) to ensure that the _transient_accumulated_data_ also contains values from the previous iterations. - -#### Verifying the constant data. - -It verifies that: - -- The _tx_context_ in the _[constant_data](#constantdata)_ matches the _tx_context_ in the _[transaction_request](#transactionrequest)_. -- The _header_ must align with the one used in the private function circuit, as verified [earlier](#verifying-the-public-inputs-of-the-private-function-circuit). - -## Private Inputs - -### _TransactionRequest_ - -Data that represents the caller's intent. - -| Field | Type | Description | -| --------------- | ------------------------------------------- | -------------------------------------------- | -| _origin_ | _AztecAddress_ | The Aztec address of the transaction sender. | -| _function_data_ | _[FunctionData](#functiondata)_ | Data of the function being called. | -| _args_hash_ | _field_ | Hash of the function arguments. | -| _tx_context_ | _[TransactionContext](#transactioncontext)_ | Information about the transaction. | - -### _PrivateCall_ - -Data that holds details about the current private function call. - -| Field | Type | Description | -| ---------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------- | -| _call_stack_item_ | _[PrivateCallStackItem](#privatecallstackitem)_ | Information about the current private function call. | -| _proof_ | _Proof_ | Proof of the private function circuit. | -| _vk_ | _VerificationKey_ | Verification key of the private function circuit. | -| _bytecode_hash_ | _field_ | Hash of the function bytecode. | -| _contract_data_ | _[ContractInstance](../contract-deployment/instances.md#structure)_ | Data of the contract instance being called. | -| _contract_class_data_ | _[ContractClassData](#contractclassdata)_ | Data of the contract class. | -| _function_leaf_membership_witness_ | _[MembershipWitness](#membershipwitness)_ | Membership witness for the function being called. | - -## Public Inputs - -### _ConstantData_ - -Data that remains the same throughout the entire transaction. - -| Field | Type | Description | -| -------------- | -------------------------------------------------- | ------------------------------------------------------------- | -| _header_ | _[Header](./private-function.md#header)_ | Header of a block which was used when assembling the tx. | -| _tx_context_ | _[TransactionContext](#transactioncontext)_ | Context of the transaction. | - -### _TransientAccumulatedData_ - -| Field | Type | Description | -| ------------------------------------------- | -------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -| _note_hash_contexts_ | [_[NoteHashContext](#notehashcontext)_; _C_] | Note hashes with extra data aiding verification. | -| _nullifier_contexts_ | [_[NullifierContext](#nullifiercontext)_; _C_] | Nullifiers with extra data aiding verification. | -| _l2_to_l1_message_contexts_ | [_[L2toL1MessageContext](#l2tol1messagecontext)_; _C_] | L2-to-l1 messages with extra data aiding verification. | -| _read_request_contexts_ | [_[ReadRequestContext](#readrequestcontext)_; _C_] | Requests to read notes in the note hash tree. | -| _nullifier_key_validation_request_contexts_ | [_[NullifierKeyValidationRequestContext](#nullifierkeyvalidationrequestcontext)_; _C_] | Requests to validate nullifier keys. | -| _unencrypted_log_hash_contexts_ | [_[EncryptedLogHashContext](#encryptedloghashcontext)_; _C_] | Hashes of the unencrypted logs with extra data aiding verification. | -| _encrypted_log_hash_contexts_ | [_[UnencryptedLogHashContext](#unencryptedloghashcontext)_; _C_] | Hashes of the encrypted logs with extra data aiding verification. | -| _encrypted_note_preimage_hash_contexts_ | [_[EncryptedNotePreimageHashContext](#encryptednotepreimagehash)_; _C_] | Hashes of the encrypted note preimages with extra data aiding verification. | -| _private_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call private functions. | -| _public_call_requests_ | [_[CallRequest](#callrequest)_; _C_] | Requests to call publics functions. | - -> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. - -## Types - -#### _FunctionData_ - -| Field | Type | Description | -| ------------------- | ---------------------------------- | --------------------------------------------------- | -| _function_selector_ | _u32_ | Selector of the function being called. | -| _function_type_ | private \| public \| unconstrained | Type of the function being called. | -| _is_internal_ | _bool_ | A flag indicating whether the function is internal. | - -#### _ContractClassData_ - -| Field | Type | Description | -| ------------------------- | -------------- | ------------------------------------------------------------------ | -| _version_ | _u8_ | Version identifier. | -| _registerer_address_ | _AztecAddress_ | Address of the canonical contract used for registering this class. | -| _artifact_hash_ | _field_ | Hash of the contract artifact. | -| _private_functions_ | _field_ | Merkle root of the private function tree. | -| _public_functions_ | _field_ | Merkle root of the public function tree. | -| _unconstrained_functions_ | _field_ | Merkle root of the unconstrained function tree. | - -#### _TransactionContext_ - -| Field | Type | Description | -| ---------- | ------------------------------------ | ---------------------------- | -| _tx_type_ | standard \| fee_paying \| fee_rebate | Type of the transaction. | -| _chain_id_ | _field_ | Chain ID of the transaction. | -| _version_ | _field_ | Version of the transaction. | - -#### _PrivateCallStackItem_ - -| Field | Type | Description | -| ------------------ | -------------------------------------------------------------------- | --------------------------------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract on which the function is invoked. | -| _function_data_ | _[FunctionData](#functiondata)_ | Data of the function being called. | -| _public_inputs_ | _[PrivateFunctionPublicInputs](./private-function.md#public-inputs)_ | Public inputs of the private function circuit. | -| _counter_start_ | _field_ | Counter at which the function call was initiated. | -| _counter_end_ | _field_ | Counter at which the function call ended. | - -#### _CallRequest_ - -| Field | Type | Description | -| ----------------- | --------------------------------- | --------------------------------------------- | -| _hash_ | _field_ | Hash of the call stack item. | -| _caller_contract_ | _AztecAddress_ | Address of the contract calling the function. | -| _caller_context_ | _[CallerContext](#callercontext)_ | Context of the contract calling the function. | -| _counter_start_ | _field_ | Counter at which the call was initiated. | -| _counter_end_ | _field_ | Counter at which the call ended. | - -#### _CallerContext_ - -| Field | Type | Description | -| ------------------ | -------------- | ---------------------------------------------------- | -| _msg_sender_ | _AztecAddress_ | Address of the caller contract. | -| _storage_contract_ | _AztecAddress_ | Storage contract address of the caller contract. | -| _is_static_call_ | _bool_ | A flag indicating whether the call is a static call. | - -#### _NoteHashContext_ - -| Field | Type | Description | -| ------------------- | -------------- | -------------------------------------------------------- | -| _value_ | _field_ | Hash of the note. | -| _counter_ | _field_ | Counter at which the note hash was created. | -| _nullifier_counter_ | _field_ | Counter at which the nullifier for the note was created. | -| _contract_address_ | _AztecAddress_ | Address of the contract the note was created. | - -#### _NullifierContext_ - -| Field | Type | Description | -| ------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------ | -| _value_ | _field_ | Value of the nullifier. | -| _counter_ | _field_ | Counter at which the nullifier was created. | -| _note_hash_counter_ | _field_ | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | -| _contract_address_ | _AztecAddress_ | Address of the contract the nullifier was created. | - -#### _L2toL1MessageContext_ - -| Field | Type | Description | -| ------------------------- | -------------- | ------------------------------------------------ | -| _value_ | _field_ | L2-to-l2 message. | -| _portal_contract_address_ | _AztecAddress_ | Address of the portal contract to the contract. | -| _contract_address_ | _AztecAddress_ | Address of the contract the message was created. | - -#### _ReadRequestContext_ - -| Field | Type | Description | -| ------------------ | -------------- | --------------------------------------------- | -| _note_hash_ | _field_ | Hash of the note to be read. | -| _counter_ | _field_ | Counter at which the request was made. | -| _contract_address_ | _AztecAddress_ | Address of the contract the request was made. | - -#### _NullifierKeyValidationRequestContext_ - -| Field | Type | Description | -| ------------------ | -------------- | ---------------------------------------------------------- | -| _public_key_ | _field_ | Nullifier public key of an account. | -| _secret_key_ | _field_ | Secret key of an account siloed with the contract address. | -| _contract_address_ | _AztecAddress_ | Address of the contract the request was made. | - -#### _UnencryptedLogHashContext_ - -| Field | Type | Description | -| ------------------ | -------------- | -------------------------------------------- | -| _hash_ | _field_ | Hash of the unencrypted log. | -| _length_ | _field_ | Number of fields of the log preimage. | -| _counter_ | _field_ | Counter at which the hash was emitted. | -| _contract_address_ | _AztecAddress_ | Address of the contract the log was emitted. | - -#### _EncryptedLogHashContext_ - -| Field | Type | Description | -| ------------------ | -------------- | -------------------------------------------- | -| _hash_ | _field_ | Hash of the encrypted log. | -| _length_ | _field_ | Number of fields of the log preimage. | -| _randomness_ | _field_ | A random value to hide the contract address. | -| _counter_ | _field_ | Counter at which the hash was emitted. | -| _contract_address_ | _AztecAddress_ | Address of the contract the log was emitted. | - -#### _EncryptedNotePreimageHashContext_ - -| Field | Type | Description | -| ------------------- | -------------- | -------------------------------------------- | -| _hash_ | _field_ | Hash of the encrypted note preimage. | -| _length_ | _field_ | Number of fields of the note preimage. | -| _note_hash_counter_ | _field_ | Counter of the corresponding note hash. | -| _counter_ | _field_ | Counter at which the hash was emitted. | -| _contract_address_ | _AztecAddress_ | Address of the contract the log was emitted. | - -#### _MembershipWitness_ - -| Field | Type | Description | -| -------------- | ------------ | ------------------------------------- | -| _leaf_index_ | _field_ | Index of the leaf in the tree. | -| _sibling_path_ | [_field_; H] | Sibling path to the leaf in the tree. | - -> **H** represents the height of the tree. diff --git a/yellow-paper/docs/circuits/private-kernel-initial.mdx b/yellow-paper/docs/circuits/private-kernel-initial.mdx new file mode 100644 index 00000000000..8115a11af77 --- /dev/null +++ b/yellow-paper/docs/circuits/private-kernel-initial.mdx @@ -0,0 +1,898 @@ +# Private Kernel Circuit - Initial + + + +## Requirements + +In the **initial** kernel iteration, the process involves taking a [`transaction_request`](#transactionrequest) and private call data , performing checks on this data (see below), and preparing the necessary data for subsequent circuits to operate. This "initial" circuit is an optimization over the [inner private kernel circuit](./private-kernel-inner.mdx), as there is no "previous kernel" to verify at the beginning of a transaction. Additionally, this circuit executes tasks that need only occur once per transaction. + +### Key Checks within this Circuit + +#### This first function call of the transaction must match the caller's intent + +The following data in the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall) must match the corresponding fields of the user's [`private_inputs`](#private-inputs)[`.transaction_request`](#transactionrequest): + +- `contract_address` +- `function_data` +- `args_hash`: Hash of the function arguments. + +> Notice: a `transaction_request` doesn't explicitly contain a signature. Aztec implements [account abstraction](../addresses-and-keys/keys-requirements.md#authorization-keys), so the process for authorizing a transaction (if at all) is dictated by the logic of the functions of that transaction. In particular, an account contract can be called as an 'entrypoint' to a transaction, and there, custom authorization logic can be executed. + +#### The function call must be a [private function](./private-function.md) + +For the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.function_data`](#functiondata), the circuit verifies that: + +- It must be a private function: + - `function_data.function_type == private` +- It must not be an internal function: + - `function_data.is_internal == false` + +#### It must be a standard [synchronous function call](../calls/sync-calls.md) + + + +For the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs)[`.call_context: CallContext`](./private-function.md#callcontext), the circuit checks that: + +- It must not be a delegate call: + - `call_context.is_delegate_call == false` +- It must not be a static call: + - `call_context.is_static_call == false` + + + +#### The `transaction_request` must be unique + + + +It must emit the hash of the [`private_inputs.transaction_request`](#transactionrequest) as the **first** nullifier. + + + +The hash is computed as: + +```js +let { origin, function_data, args_hash, tx_context } = + private_inputs.transaction_request; +let tx_hash = hash(origin, function_data.hash(), args_hash, tx_context.hash()); +``` + +Where `function_data.hash()` and `tx_context.hash()` are the hashes of the serialized field elements. + +This nullifier serves multiple purposes: + +- Identifying a transaction. +- Non-malleability. Preventing the signature of a transaction request from being reused in another transaction. +- Generating values that should be maintained within the transaction's scope. For example, it is utilized to [compute the nonces](./private-kernel-tail.md#siloing-values) for all the note hashes in a transaction. + + + +> Note that the final transaction data is not deterministic for a given transaction request. The production of new notes, the destruction of notes, and various other values are likely to change based on the time and conditions when a transaction is being composed. However, the intricacies of implementation should not be a concern for the entity initiating the transaction. + +### Processing a Private Function Call + +#### The function being called must exist within the contract class of the called `contract_address` + + + +With the following data provided from [`private_inputs`](#private-inputs)[`.private_call`](#privatecall): + +- `contract_address` in `private_call`[`.call_stack_item`](#privatecallstackitem). +- `contract_instance` +- `contract_class` +- `function_data` in `private_call`[`.call_stack_item`](#privatecallstackitem). + +This circuit validates the existence of the function in the contract through the following checks: + + + +1. Verify that the `contract_address` can be derived from the `contract_instance`: + + Refer to the details [here](../contract-deployment/instances.md#address) for the process of computing the address for a contract instance. + +2. Verify that the `contract_instance.contract_class_id` can be derived from the given `contract_class`: + + Refer to the details [here](../contract-deployment/classes.md#class-identifier) for the process of computing the _contract_class_id_. + +3. Verify that _contract_class_data.private_functions_ includes the function being called: + + 1. Compute the hash of the verification key: + - `vk_hash = hash(private_call.vk)` + 2. Compute the function leaf: + - `hash(function_data.selector, vk_hash, private_call.bytecode_hash)` + 3. Perform a membership check; that the function leaf exists within the function tree, where: + - The index and sibling path are provided through [`private_call`](#privatecall)`.function_leaf_membership_witness`. + - The root is `contract_class.private_functions`. + +#### The private function proof must verify + +It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs of the [private function circuit](./private-function.md). +I.e. `private_inputs.private_call.vk`, `private_inputs.private_call.proof`, and `private_inputs.private_call.call_stack_item.public_inputs`. + +#### Validate the counters. + +It validates that all of the counters follow the rules of the protocol. + +1. For the [`private_inputs.private_call.call_stack_item`](#privatecallstackitem): + + - The `counter_start` must be `0`. + - This check can be skipped for [inner private kernel circuit](./private-kernel-inner.mdx#verifying-the-counters). + - The `counter_end` must be strictly greater than the `counter_start`. + +2. Validate the items in each ordered array of [private_inputs.private_call.call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs). + +The "ordered arrays" include: + +- `note_hashes` +- `nullifiers` +- `read_requests` +- `unencrypted_log_hashes` +- `encrypted_log_hashes` +- `encrypted_note_preimage_hashes` + + + +Notice that each element of these arrays is a [type](./private-function.md#types) that contains a `counter`. They are so-called "ordered arrays" because the counters must be in a strictly-increasing order within an array. + +For each element of each "ordered array" of [`private_inputs.private_call.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs): + +- The `counter` of the first element must be strictly greater than the `counter_start` of the `private_inputs.private_call.call_stack_item`. +- The `counter` of each subsequent element must be strictly greater than the `counter` of the previous item. +- The `counter` of the last element must be strictly less than the `counter_end` of the `private_inputs.private_call.call_stack_item`. + + + + +3. For the `N` non-empty requests in [`public_inputs`](#public-inputs)[`.transient_accumulated_data`](#transientaccumulateddata)[`.private_call_requests: [CallRequest; _]`](#callrequest): + + + + + +> `N` is the number of non-zero entries in [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs)[`.private_call_stack_item_hashes: [Field; _]`]. + + + +- The `counter_end` of each request must be strictly greater than its `counter_start`. +- The `counter_end` of the first request must be strictly less than the `counter_end` of the `call_stack_item`. +- The `counter_end` of the second and each of the subsequent requests must be strictly less than the `counter_start` of the previous request. +- The `counter_start` of the last request must be strictly greater than the `counter_start` of the `call_stack_item`. + +4. For the `N` non-empty requests in [`public_inputs.transient_accumulated_data`](#transientaccumulateddata)`.public_call_requests`: + + > `N` is the number of non-zero entries in the `public_call_stack_item_hashes` in [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.public_inputs`](./private-function.md#public-inputs). + + + +- The `counter_start` of the first request must be strictly greater than the `counter_start` of the `call_stack_item`. +- The `counter_start` of each subsequent request must be strictly greater than the `counter_start` of the previous item. +- The `counter_start` of the last item must be strictly less than the `counter_end` of the `call_stack_item`. + +> Note that the `counter_end` of each public call request is unknown at this point . Both the `counter_start` and `counter_end` of a `PublicCallStackItem` will be [recalibrated](./public-kernel-initial.md#recalibrating-counters) in the initial _public_ kernel circuit following the simulation of all public function calls. + +> Note that, for this initial private kernel circuit, all values within the [`public_inputs.transient_accumulated_data`](#transientaccumulateddata) originate from the [`private_call`](#privatecall). However, this process of counter verification is also applicable to the [inner private kernel circuit](./private-kernel-inner.mdx#verifying-the-counters), where the `transient_accumulated_data` comprises values from previous iterations and the current function call. Therefore, only the last `N` requests (which correspond to the new requests which originated from the `private_inputs.private_call`) need to be checked in the above operations. + +### Validating Public Inputs + +#### Verifying the `TransientAccumulatedData`. + +The various side effects of the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs: PrivateFunctionPublicInputs`](./private-function.md#public-inputs) are formatted and pushed to the various arrays of the [`public_inputs`](#public-inputs)[`.transient_accumulated_data: TransientAccumulatedData`](#transientaccumulateddata). + +This circuit verifies that the values in [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs: PrivateFunctionPublicInputs`](./private-function.md#public-inputs) are aggregated into the various arrays of the [`public_inputs`](#public-inputs)[`.transient_accumulated_data: TransientAccumulatedData`](#transientaccumulateddata) correctly. + +1. Ensure that the specified values in the following arrays match those in the corresponding arrays in the `private_function_public_inputs`: + +- `note_hash_contexts` + - `value`, `counter` +- `nullifier_contexts` + - `value`, `counter` +- `l2_to_l1_message_contexts` + - `value` +- `read_request_contexts` + - `note_hash`, `counter` +- `nullifier_key_validation_request` + - `public_key`, `secret_key` +- `unencrypted_log_hash_contexts` + - `hash`, `length`, `counter` +- `encrypted_log_hash_contexts` + - `hash`, `length`, `randomness`, `counter` +- `encrypted_note_preimage_hash_contexts` + - `hash`, `length`, `counter`, `note_hash_counter` +- `private_call_requests` + - `hash`, `counter` +- `public_call_requests` + - `hash`, `counter` + +2. Check that the hashes in the `private_call_requests` align with the values in the `private_call_stack_item_hashes` in the `private_function_public_inputs`, but in **reverse** order. + + > It's important that the `private_call_requests` are arranged in reverse order to ensure they are executed in chronological order. + +3. For each non-empty call request in both `public_inputs.transient_accumulated_data.private_call_requests` and `public_inputs.transient_accumulated_data.public_call_requests`: + + - The `caller_contract_address` equals the [`private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.contract_address`]. + - The following values in `caller_context` are either empty or align with the values in the `private_inputs.private_call.call_stack_item.public_inputs.call_context`: + - `(caller_context.msg_sender == 0) & (caller_context.storage_contract_address == 0)` + - Or `(caller_context.msg_sender == call_context.msg_sender) & (caller_context.storage_contract_address == call_context.storage_contract_address)` + - The `is_static_call` flag must be propagated: + - `caller_context.is_static_call == call_context.is_static_call` + + + +> The caller context in a call request may be empty for standard calls. This precaution is crucial to prevent information leakage, particularly as revealing the _msg_sender_ of this private function when calling a public function could pose security risks. + +4. For each non-empty item in the following arrays, its `contract_address` must equal the `storage_contract_address` in `private_inputs.private_call.call_stack_item.public_inputs.call_context`: + + - `note_hash_contexts` + - `nullifier_contexts` + - `l2_to_l1_message_contexts` + - `read_request_contexts` + - `nullifier_key_validation_request_contexts` + - `unencrypted_log_hash_contexts` + - `encrypted_log_hash_contexts` + - `encrypted_note_preimage_hash_contexts` + + > Ensuring the alignment of the contract addresses is crucial, as it is later used to [silo the values](./private-kernel-tail.md#siloing-values) and to establish associations with values within the same contract. + +5. For each non-empty item in `l2_to_l1_message_contexts`, its `portal_contract_address` must equal the `portal_contract_address` defined in `private_function_public_inputs.call_context`. + + +6. For each `note_hash_context: NoteHashContext` in the `note_hash_contexts`, validate its `nullifier_counter`. The value of the `nullifier_counter` can be: + + - Zero: if the note is not nullified in the same transaction. + - Strictly greater than `note_hash.counter`: if the note is nullified in the same transaction. + + > Nullifier counters are used in the [reset private kernel circuit](./private-kernel-reset.md#read-request-reset-private-kernel-circuit) to ensure a read happens **before** a transient note is nullified. + + > Zero can be used to indicate a non-existing transient nullifier, as this value can never serve as the counter of a nullifier. It corresponds to the `counter_start` of the first function call. + +> Note that the verification process outlined above is also applicable to the inner private kernel circuit. However, given that the `transient_accumulated_data` for the inner private kernel circuit comprises both values from previous iterations and the `private_call`, the above process specifically targets the values stemming from the `private_call`. The inner kernel circuit performs an [extra check](./private-kernel-inner.mdx#verifying-the-transient-accumulated-data) to ensure that the `transient_accumulated_data` also contains values from the previous iterations. + +#### Verifying the constant data. + +It verifies that: + +- The `tx_context` in the [`constant_data`](#constantdata) matches the `tx_context` in the [`transaction_request`](#transactionrequest). +- The `block_header` must align with the one used in the private function circuit, as verified [earlier](#verifying-the-public-inputs-of-the-private-function-circuit). + +## Diagram + +This diagram flows from the private inputs (which can be considered "inputs") to the public inputs (which can be considered "outputs"). + +--- + +Key: + +
+ +```mermaid +classDiagram +direction LR +class ParentClass { + child: ChildClass +} +class ChildClass { + x +} +class A { + a +} +class B { + a +} +class C { + c +} +class D { + c +} +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). +``` + +
+ +--- + +The diagram: + + + + + +
+
+ +```mermaid +classDiagram +direction TB + +class PrivateInputs { + transaction_request: TransactionRequest + private_call: PrivateCall +} +PrivateInputs *-- TransactionRequest: transaction_request +PrivateInputs *-- PrivateCall: private_call + +class TransactionRequest { + origin: AztecAddress + function_data: FunctionData + args_hash: field + tx_context: TransactionContext +} +TransactionRequest *-- FunctionData: function_data +TransactionRequest *-- TransactionContext: tx_context + +TransactionRequest ..> ConstantData: tx_context + +class PrivateCall { + call_stack_item: PrivateCallStackItem + proof: Proof + vk: VerificationKey + bytecode_hash: field + contract_instance: ContractInstance + contract_class: ContractClass + function_leaf_membership_witness: MembershipWitness +} +PrivateCall *-- PrivateCallStackItem: call_stack_item +PrivateCall *-- Proof: proof +PrivateCall *-- VerificationKey: vk +PrivateCall *-- ContractInstance: contract_instance +PrivateCall *-- ContractClass: contract_class +PrivateCall *-- MembershipWitness: function_leaf_membership_witness + +VerificationKey ..> FUNCTION_EXISTENCE_CHECK: Check vk exists within function leaf +FunctionData ..> FUNCTION_EXISTENCE_CHECK: Check function_data exists within function leaf +MembershipWitness ..> FUNCTION_EXISTENCE_CHECK: Check function leaf exists within \nprivate function tree + +FUNCTION_EXISTENCE_CHECK .. ContractClass: computed_root == private_functions + +VerificationKey ..> PROOF_VERIFICATION +Proof ..> PROOF_VERIFICATION +PrivateFunctionPublicInputs ..> PROOF_VERIFICATION + +ContractClass .. ContractInstance: hash(contract_class) == contract_class_id + +class ContractClass { + version: u8 + registerer_address: AztecAddress + artifact_hash: field + private_functions: field + public_functions: field + unconstrained_functions: field +} + +class TransactionContext { + tx_type: standard|fee_paying|fee_rebate + chain_id: field + version: field +} + +class PrivateCallStackItem { + contract_address: AztecAddress + function_data: FunctionData + public_inputs: PrivateFunctionPublicInputs + counter_start: field + counter_end: field +} +PrivateCallStackItem *-- FunctionData: function_data +PrivateCallStackItem *-- PrivateFunctionPublicInputs: public_inputs + +PrivateCallStackItem .. TransactionRequest: function_data==function_data + + +PrivateCallStackItem .. CallContext: if is_delegatecall then\n contract_address == msg_sender \nelse \n contract_address == storage_contract_address + +PrivateCallStackItem .. PrivateFunctionPublicInputs: Validate counter_start & counter_end\nvs. the counters of the ordered arrays + +PrivateCallStackItem .. CallRequest: Validate all counter_start\n& counter_end values. + +TransactionRequest .. PrivateFunctionPublicInputs: args_hash == args_hash + +TransactionRequest .. CallContext: origin == msg_sender + +ContractInstance .. PrivateCallStackItem: hash(contract_instance) == contract_address + +class FunctionData { + function_selector: u32 + function_type: private|public|unconstrained + is_internal: bool +} + +class PrivateFunctionPublicInputs { + call_context: CallContext + args_hash: field + return_values: List~field~ + note_hashes: List~NoteHash~ + nullifiers: List~Nullifier~ + l2_to_l1_messages: List~field~ + read_requests: List~ReadRequest~ + nullifier_key_validation_requests: List~NullifierKeyValidationRequest~ + unencrypted_log_hashes: List~UnencryptedLogHash~ + encrypted_log_hashes: List~EncryptedLogHash~ + encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ + private_call_stack_item_hashes: List~field~ + public_call_stack_item_hashes: List~field~ + block_header: BlockHeader + chain_id: field + version: field +} +PrivateFunctionPublicInputs *-- CallContext: call_context +PrivateFunctionPublicInputs *-- NoteHash: note_hashes +PrivateFunctionPublicInputs *-- Nullifier: nullifiers +PrivateFunctionPublicInputs *-- ReadRequest: read_requests +PrivateFunctionPublicInputs *-- NullifierKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes +PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes +PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes +PrivateFunctionPublicInputs *-- BlockHeader: block_header + +TransactionContext .. PrivateFunctionPublicInputs: chain_id==chain_id\nversion==version + +class FUNCTION_EXISTENCE_CHECK { + Check the vk, function_data, + exist within the private function tree root +} +class PROOF_VERIFICATION { + Verify the proof +} + + +class CallContext { + msg_sender: AztecAddress + storage_contract_address: AztecAddress + portal_contract_address: AztecAddress + is_delegate_call: bool + is_static_call: bool +} +CallContext ..> CallerContext : call_context + +CallContext .. NoteHashContext: storage_contract_address\n== contract_address +CallContext .. NullifierContext: storage_contract_address\n== contract_address +CallContext .. ReadRequestContext: storage_contract_address\n== contract_address +CallContext .. NullifierKeyValidationRequestContext: storage_contract_address\n== contract_address +CallContext .. UnencryptedLogHashContext: storage_contract_address\n== contract_address +CallContext .. EncryptedLogHashContext: storage_contract_address\n== contract_address +CallContext .. EncryptedNotePreimageHashContext: storage_contract_address\n== contract_address + + +PrivateFunctionPublicInputs ..> L2ToL1MessageContext: l2_to_l1_messages\n->l2_to_l1_message_contexts + +class NoteHash { + value: field + counter: field +} +NoteHash ..> NoteHashContext: note_hashes\n->note_hash_contexts + +class Nullifier { + value: field + counter: field + note_hash_counter: field +} +Nullifier ..> NullifierContext: nullifiers\n->nullifier_contexts + +class ReadRequest { + note_hash: field + counter: field +} +ReadRequest ..> ReadRequestContext: read_requests\n->read_request_contexts + +class NullifierKeyValidationRequest { + public_key: GrumpkinPoint + secret_key: fq +} +NullifierKeyValidationRequest ..> NullifierKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts + +class UnencryptedLogHash { + hash: field + length: field + counter: field +} +UnencryptedLogHash ..> UnencryptedLogHashContext: unencrypted_log_hashes\n->unencrypted_log_hash_contexts + +class EncryptedLogHash { + hash: field + length: field + counter: field + randomness: field +} +EncryptedLogHash ..> EncryptedLogHashContext: encrypted_log_hashes\n->encrypted_log_hash_contexts + +class EncryptedNotePreimageHash { + hash: field + length: field + counter: field + note_hash_counter: field +} +EncryptedNotePreimageHash ..> EncryptedNotePreimageHashContext: encrypted_note_preimage_hashes\n->encrypted_note_preimage_hash_contexts + + +class BlockHeader { + note_hash_tree_root: field + nullifier_tree_root: field + l1_to_l2_message_tree_root: field + public_data_tree_root: field + archive_tree_root: field + global_variables_hash: field +} + +class CallRequest { + call_stack_item_hash: field + caller_contract: AztecAddress + caller_context: CallerContext + counter_start: field + counter_end: field +} +CallerContext --* CallRequest : caller_context + +PrivateFunctionPublicInputs ..> CallRequest: private_call_stack_item_hash->call_stack_item_hash\npublic_call_stack_item_hash->call_stack_item_hash + +class CallerContext { + msg_sender: AztecAddress + storage_contract_address: AztecAddress + is_static_call: bool +} + + + +class NoteHashContext { + value: field + counter: field + nullifier_counter: field + contract_address: AztecAddress +} + +class NullifierContext { + value: field + counter: field + note_hash_counter: field + contract_address: AztecAddress +} + +class L2ToL1MessageContext { + value: field + portal_contract_address: AztecAddress + contract_address: AztecAddress +} + +class ReadRequestContext { + note_hash: field + counter: field + contract_address: AztecAddress +} + +class NullifierKeyValidationRequestContext { + public_key: field + secret_key: field + contract_address: AztecAddress +} + +class UnencryptedLogHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress +} + +class EncryptedLogHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress + randomness: field +} + +class EncryptedNotePreimageHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress + note_hash_counter: field +} + +class MembershipWitness { + leaf_index: field + sibling_path: List~field~ +} + +class ContractInstance { + version: u8 + deployer_address: AztecAddress + salt: field + contract_class_id: field + contract_args_hash: field + portal_contract_address: EthereumAddress + public_keys_hash: Field +} + +class TransientAccumulatedData { + note_hash_contexts: List~NoteHashContext~ + nullifier_contexts: List~NullifierContext~ + l2_to_l1_message_contexts: List~L2ToL1MessageContext~ + read_request_contexts: List~ReadRequestContext~ + nullifier_key_validation_request_contexts: List~NullifierKeyValidationRequestContext~ + unencrypted_log_hash_contexts: List~UnencryptedLogHashContext~ + encrypted_log_hash_contexts: List~EncryptedLogHashContext~ + encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ + private_call_requests: List~CallRequest~ + public_call_requests: List~CallRequest~ +} +NoteHashContext --* TransientAccumulatedData: note_hash_contexts +NullifierContext --* TransientAccumulatedData: nullifier_contexts +L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts +ReadRequestContext --* TransientAccumulatedData: read_request_contexts +NullifierKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts +EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts +EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts +CallRequest --* TransientAccumulatedData: private_call_requests +CallRequest --* TransientAccumulatedData: public_call_requests + +class ConstantData { + block_header: BlockHeader + tx_context: TransactionContext +} +BlockHeader ..> ConstantData: block_header + +class PublicInputs { + constant_data: ConstantData + transient_accumulated_data: TransientAccumulatedData +} +ConstantData --* PublicInputs : constant_data +TransientAccumulatedData --* PublicInputs: transient_accumulated_data + +``` + +
+
+ +## `PrivateInputs` + +| Field | Type | Description | +| --------------------- | ------------------------------------------- | ----------- | +| `transaction_request` | [`TransactionRequest`](#transactionrequest) | | +| `private_call` | [`PrivateCall`](#privatecall) | | + +### `TransactionRequest` + +Data that represents the caller's intent. + +| Field | Type | Description | +| --------------- | ------------------------------------------- | -------------------------------------------- | +| `origin` | `AztecAddress` | The Aztec address of the transaction sender. | +| `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | +| `args_hash` | `Field` | Hash of the function arguments. | +| `tx_context` | [`TransactionContext`](#transactioncontext) | Information about the transaction. | + +### `PrivateCall` + +Data that holds details about the current private function call. + +| Field | Type | Description | +| ---------------------------------- | ------------------------------------------------------------------- | ---------------------------------------------------- | +| `call_stack_item` | [`PrivateCallStackItem`](#privatecallstackitem) | Information about the current private function call. | +| `proof` | `Proof` | Proof of the private function circuit. | +| `vk` | `VerificationKey` | Verification key of the private function circuit. | +| `bytecode_hash` | `Field` | Hash of the function bytecode. | +| `contract_instance` | [`ContractInstance`](../contract-deployment/instances.md#structure) | Data of the contract instance being called. | +| `contract_class` | [`ContractClass`](#contractclassdata) | Data of the contract class. | +| `function_leaf_membership_witness` | [`MembershipWitness`](#membershipwitness) | Membership witness for the function being called. | + +## `PublicInputs` + +| Field | Type | Description | +| ---------------------------- | ------------------------------------------------------- | ----------- | +| `constant_data` | [`ConstantData`](#constantdata) | | +| `transient_accumulated_data` | [`TransientAccumulatedData`](#transientaccumulateddata) | | + +### `ConstantData` + +Data that remains the same throughout the entire transaction. + +| Field | Type | Description | +| ------------ | ------------------------------------------- | -------------------------------------------------------- | +| `header` | [`Header`](./private-function.md#header) | Header of a block which was used when assembling the tx. | +| `tx_context` | [`TransactionContext`](#transactioncontext) | Context of the transaction. | + +### `TransientAccumulatedData` + + + +| Field | Type | Description | +| ------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | +| `note_hash_contexts` | [`[NoteHashContext; C]`](#notehashcontext) | Note hashes with extra data aiding verification. | +| `nullifier_contexts` | [`[NullifierContext; C]`](#nullifiercontext) | Nullifiers with extra data aiding verification. | +| `l2_to_l1_message_contexts` | [`[L2toL1MessageContext; C]`](#l2tol1messagecontext) | L2-to-l1 messages with extra data aiding verification. | +| `read_request_contexts` | [`[ReadRequestContext; C]`](#readrequestcontext) | Requests to read notes in the note hash tree. | +| `nullifier_key_validation_request_contexts` | [`[NullifierKeyValidationRequestContext; C]`](#nullifierkeyvalidationrequestcontext) | Requests to validate nullifier keys. | +| `unencrypted_log_hash_contexts` | [`[UnencryptedLogHashContext; C]`](#unencryptedloghashcontext) | Hashes of the unencrypted logs with extra data aiding verification. | +| `encrypted_log_hash_contexts` | [`[EncryptedLogHashContext; C]`](#encryptedloghashcontext) | Hashes of the encrypted logs with extra data aiding verification. | +| `encrypted_note_preimage_hash_contexts` | [`[EncryptedNotePreimageHashContext; C]`](#encryptednotepreimagehash) | Hashes of the encrypted note preimages with extra data aiding verification. | +| `private_call_requests` | [`[CallRequest; C]`](#callrequest) | Requests to call private functions. | +| `public_call_requests` | [`[CallRequest; C]`](#callrequest) | Requests to call publics functions. | + +> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. + +## Types + +### `FunctionData` + + + + +| Field | Type | Description | +| ------------------- | ---------------------------------- | --------------------------------------------------- | +| `function_selector` | `u32` | Selector of the function being called. | +| `function_type` | `private | public | unconstrained` | Type of the function being called. | +| `is_internal` | `bool` | A flag indicating whether the function is internal. | + + + +### `ContractClass` + + + + +| Field | Type | Description | +| ------------------------- | -------------- | ------------------------------------------------------------------ | +| `version` | `u8` | Version identifier. | +| `registerer_address` | `AztecAddress` | Address of the canonical contract used for registering this class. | +| `artifact_hash` | `Field` | Hash of the contract artifact. | +| `private_functions` | `Field` | Merkle root of the private function tree. | +| `public_functions` | `Field` | Merkle root of the public function tree. | +| `unconstrained_functions` | `Field` | Merkle root of the unconstrained function tree. | + +### `TransactionContext` + + +| Field | Type | Description | +| ---------- | ------------------------------------ | ---------------------------- | +| `tx_type` | `standard | fee_paying | fee_rebate` | Type of the transaction. | +| `chain_id` | `Field` | Chain ID of the transaction. | +| `version` | `Field` | Version of the transaction. | + +### `PrivateCallStackItem` + +| Field | Type | Description | +| ------------------ | -------------------------------------------------------------------- | --------------------------------------------------------- | +| `contract_address` | `AztecAddress` | Address of the contract on which the function is invoked. | +| `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | +| `public_inputs` | [`PrivateFunctionPublicInputs`](./private-function.md#public-inputs) | Public inputs of the private function circuit. | +| `counter_start` | `Field` | Counter at which the function call was initiated. | +| `counter_end` | `Field` | Counter at which the function call ended. | + + + +### `CallRequest` + + + + +| Field | Type | Description | +| ---------------------- | --------------------------------- | --------------------------------------------- | +| `call_stack_item_hash` | `Field` | Hash of the call stack item. | +| `caller_contract` | `AztecAddress` | Address of the contract calling the function. | +| `caller_context` | [`CallerContext`](#callercontext) | Context of the contract calling the function. | +| `counter_start` | `Field` | Counter at which the call was initiated. | +| `counter_end` | `Field` | Counter at which the call ended. | + +### `CallerContext` + + + +| Field | Type | Description | +| ------------------ | -------------- | ---------------------------------------------------- | +| `msg_sender` | `AztecAddress` | Address of the caller contract. | +| `storage_contract` | `AztecAddress` | Storage contract address of the caller contract. | +| `is_static_call` | `bool` | A flag indicating whether the call is a static call. | + +### `NoteHashContext` + + + +| Field | Type | Description | +| ------------------- | -------------- | -------------------------------------------------------- | +| `value` | `Field` | Hash of the note. | +| `counter` | `Field` | Counter at which the note hash was created. | +| `nullifier_counter` | `Field` | Counter at which the nullifier for the note was created. | +| `contract_address` | `AztecAddress` | Address of the contract the note was created. | + +### `NullifierContext` + +| Field | Type | Description | +| ------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------ | +| `value` | `Field` | Value of the nullifier. | +| `counter` | `Field` | Counter at which the nullifier was created. | +| `note_hash_counter` | `Field` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | +| `contract_address` | `AztecAddress` | Address of the contract the nullifier was created. | + +### `L2toL1MessageContext` + +| Field | Type | Description | +| ------------------------- | -------------- | ------------------------------------------------ | +| `value` | `Field` | L2-to-l2 message. | +| `portal_contract_address` | `AztecAddress` | Address of the portal contract to the contract. | +| `contract_address` | `AztecAddress` | Address of the contract the message was created. | + +### `ReadRequestContext` + +| Field | Type | Description | +| ------------------ | -------------- | --------------------------------------------- | +| `note_hash` | `Field` | Hash of the note to be read. | +| `counter` | `Field` | Counter at which the request was made. | +| `contract_address` | `AztecAddress` | Address of the contract the request was made. | + +### `NullifierKeyValidationRequestContext` + +| Field | Type | Description | +| ------------------ | -------------- | ---------------------------------------------------------- | +| `public_key` | `Field` | Nullifier public key of an account. | +| `secret_key` | `Field` | Secret key of an account siloed with the contract address. | +| `contract_address` | `AztecAddress` | Address of the contract the request was made. | + +### `UnencryptedLogHashContext` + + + +| Field | Type | Description | +| ------------------ | -------------- | -------------------------------------------- | +| `hash` | `Field` | Hash of the unencrypted log. | +| `length` | `Field` | Number of fields of the log preimage. | +| `counter` | `Field` | Counter at which the hash was emitted. | +| `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | + +### `EncryptedLogHashContext` + +| Field | Type | Description | +| ------------------ | -------------- | -------------------------------------------- | +| `hash` | `Field` | Hash of the encrypted log. | +| `length` | `Field` | Number of fields of the log preimage. | +| `counter` | `Field` | Counter at which the hash was emitted. | +| `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | +| `randomness` | `Field` | A random value to hide the contract address. | + +### `EncryptedNotePreimageHashContext` + +| Field | Type | Description | +| ------------------- | -------------- | -------------------------------------------- | +| `hash` | `Field` | Hash of the encrypted note preimage. | +| `length` | `Field` | Number of fields of the note preimage. | +| `counter` | `Field` | Counter at which the hash was emitted. | +| `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | +| `note_hash_counter` | `Field` | Counter of the corresponding note hash. | + +### `MembershipWitness` + +| Field | Type | Description | +| -------------- | ------------ | ------------------------------------- | +| `leaf_index` | `Field` | Index of the leaf in the tree. | +| `sibling_path` | `[Field; H]` | Sibling path to the leaf in the tree. | + +> `H` represents the height of the tree. diff --git a/yellow-paper/docs/circuits/private-kernel-inner.md b/yellow-paper/docs/circuits/private-kernel-inner.md deleted file mode 100644 index 64bee422ae0..00000000000 --- a/yellow-paper/docs/circuits/private-kernel-inner.md +++ /dev/null @@ -1,148 +0,0 @@ -# Private Kernel Circuit - Inner - -## Requirements - -Each **inner** kernel iteration processes a private function call and the results of a previous kernel iteration. - -### Verification of the Previous Iteration - -#### Verifying the previous kernel proof. - -It verifies that the previous iteration was executed successfully with the provided proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. - -The preceding proof can be: - -- [Initial private kernel proof](./private-kernel-initial.md). -- Inner private kernel proof. -- [Reset private kernel proof](./private-kernel-reset.md). - -The previous proof and the proof for the current function call are verified using recursion. - -### Processing Private Function Call - -#### Ensuring the function being called exists in the contract. - -This section follows the same [process](./private-kernel-initial.md#ensuring-the-function-being-called-exists-in-the-contract) as outlined in the initial private kernel circuit. - -#### Ensuring the function is legitimate: - -For the _[function_data](./private-kernel-initial.md#functiondata)_ in _[private_call](#privatecall).[call_stack_item](./private-kernel-initial.md#privatecallstackitem)_, this circuit verifies that: - -- It must be a private function: - - _`function_data.function_type == private`_ - -#### Ensuring the current call matches the call request. - -The top item in the _private_call_requests_ of the _[previous_kernel](#previouskernel)_ must pertain to the current function call. - -This circuit will: - -1. Pop the request from the stack: - - - _`call_request = previous_kernel.public_inputs.transient_accumulated_data.private_call_requests.pop()`_ - -2. Compare the hash with that of the current function call: - - - _`call_request.hash == private_call.call_stack_item.hash()`_ - - The hash of the _call_stack_item_ is computed as: - - _`hash(contract_address, function_data.hash(), public_inputs.hash(), counter_start, counter_end)`_ - - Where _function_data.hash()_ and _public_inputs.hash()_ are the hashes of the serialized field elements. - -#### Ensuring this function is called with the correct context. - -For the _call_context_ in the [public_inputs](./private-function.md#public-inputs) of the _[private_call](#privatecall).[call_stack_item](./private-kernel-initial.md#privatecallstackitem)_ and the _call_request_ popped in the [previous step](#ensuring-the-current-call-matches-the-call-request), this circuit checks that: - -1. If it is a standard call: _`call_context.is_delegate_call == false`_ - - - The _msg_sender_ of the current iteration must be the same as the caller's _contract_address_: - - _`call_context.msg_sender == call_request.caller_contract_address`_ - - The _storage_contract_address_ of the current iteration must be the same as its _contract_address_: - - _`call_context.storage_contract_address == call_stack_item.contract_address`_ - -2. If it is a delegate call: _`call_context.is_delegate_call == true`_ - - - The _caller_context_ in the _call_request_ must not be empty. Specifically, the following values of the caller must not be zeros: - - _msg_sender_ - - _storage_contract_address_ - - The _msg_sender_ of the current iteration must equal the caller's _msg_sender_: - - _`call_context.msg_sender == caller_context.msg_sender`_ - - The _storage_contract_address_ of the current iteration must equal the caller's _storage_contract_address_: - - _`call_context.storage_contract_address == caller_context.storage_contract_address`_ - - The _storage_contract_address_ of the current iteration must not equal the _contract_address_: - - _`call_context.storage_contract_address != call_stack_item.contract_address`_ - -3. If it is NOT a static call: _`call_context.is_static_call == false`_ - - - The previous iteration must not be a static call: - - _`caller_context.is_static_call == false`_ - -4. If it is an internal call: _`call_stack_item.function_data.is_internal == true`_ - - - The _msg_sender_ of the current iteration must equal the _storage_contract_address_: - - _`call_context.msg_sender == call_context.storage_contract_address`_ - -#### Verifying the private function proof. - -It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs, sourced from _[private_inputs](#private-inputs).[private_call](#privatecall)_. - -This circuit verifies this proof and [the proof of the previous kernel iteration](#verifying-the-previous-kernel-proof) using recursion, and generates a single proof. This consolidation of multiple proofs into one is what allows the private kernel circuits to gradually merge private function proofs into a single proof of execution that represents the entire private section of a transaction. - -#### Verifying the public inputs of the private function circuit. - -It ensures the private function circuit's intention by checking the following in _[private_call](#privatecall).[call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs)_: - -- The _header_ must match the one in the _[constant_data](./private-kernel-initial.md#constantdata)_. -- If it is a static call (_`public_inputs.call_context.is_static_call == true`_), it ensures that the function does not induce any state changes by verifying that the following arrays are empty: - - _note_hashes_ - - _nullifiers_ - - _l2_to_l1_messages_ - - _unencrypted_log_hashes_ - - _encrypted_log_hashes_ - - _encrypted_note_preimage_hashes_ - -#### Verifying the counters. - -This section follows the same [process](./private-kernel-initial.md#verifying-the-counters) as outlined in the initial private kernel circuit. - -Additionally, it verifies that for the _[call_stack_item](#privatecallstackitem)_, the _counter_start_ and _counter_end_ must match those in the _call_request_ [popped](#ensuring-the-current-call-matches-the-call-request) from the _private_call_requests_ in a previous step. - -### Validating Public Inputs - -#### Verifying the transient accumulated data. - -The _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ in this circuit's _[public_inputs](#public-inputs)_ includes values from both the previous iterations and the _[private_call](#privatecall)_. - -For each array in the _transient_accumulated_data_, this circuit verifies that: - -1. It is populated with the values from the previous iterations, specifically: - - - _`public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]`_ - - > It's important to note that the top item in the _private_call_requests_ from the _previous_kernel_ won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). - -2. As for the subsequent items appended after the values from the previous iterations, they constitute the values from the _private_call_, and each must undergo the same [verification](./private-kernel-initial.md#verifying-the-transient-accumulated-data) as outlined in the initial private kernel circuit. - -#### Verifying the constant data. - -It verifies that the _[constant_data](./private-kernel-initial.md#constantdata)_ in the _[public_inputs](#public-inputs)_ matches the _constant_data_ in _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.md#public-inputs)_. - -## Private Inputs - -### _PreviousKernel_ - -Data of the previous kernel iteration. - -| Field | Type | Description | -| -------------------- | ------------------------------------------------------------------------------- | -------------------------------------------- | -| _public_inputs_ | _[InitialPrivateKernelPublicInputs](./private-kernel-initial.md#public-inputs)_ | Public inputs of the proof. | -| _proof_ | _Proof_ | Proof of the kernel circuit. | -| _vk_ | _VerificationKey_ | Verification key of the kernel circuit. | -| _membership_witness_ | _[MembershipWitness](./private-kernel-initial.md#membershipwitness)_ | Membership witness for the verification key. | - -### _PrivateCall_ - -The format aligns with the _[PrivateCall](./private-kernel-initial.md#privatecall)_ of the initial private kernel circuit. - -## Public Inputs - -The format aligns with the _[Public Inputs](./private-kernel-initial.md#public-inputs)_ of the initial private kernel circuit. diff --git a/yellow-paper/docs/circuits/private-kernel-inner.mdx b/yellow-paper/docs/circuits/private-kernel-inner.mdx new file mode 100644 index 00000000000..44f639181f7 --- /dev/null +++ b/yellow-paper/docs/circuits/private-kernel-inner.mdx @@ -0,0 +1,556 @@ +# Private Kernel Circuit - Inner + + + +## Requirements + +Each **inner** kernel iteration processes a private function call and the results of a previous kernel iteration. + +### Verification of the Previous Iteration + +#### Verifying the previous kernel proof. + +It verifies that the previous iteration was executed successfully with the provided proof data, verification key, and public inputs, sourced from [`private_inputs`](#private-inputs).[`previous_kernel`](#previouskernel). + +The preceding proof can be: + +- [Initial private kernel proof](./private-kernel-initial.mdx). +- Inner private kernel proof. +- [Reset private kernel proof](./private-kernel-reset.md). + +The previous proof and the proof for the current function call are verified using recursion. + + + +### Processing Private Function Call + +#### Ensuring the function being called exists in the contract. + +This section follows the same [process](./private-kernel-initial.mdx#ensuring-the-function-being-called-exists-in-the-contract) as outlined in the initial private kernel circuit. + +#### Ensuring the function is legitimate: + +For the [`function_data`](./private-kernel-initial.mdx#functiondata) in [`private_call`](#privatecall)[`.call_stack_item`](./private-kernel-initial.mdx#privatecallstackitem), this circuit verifies that: + +- It must be a private function: + - `function_data.function_type == private` + +#### Ensuring the current call matches the call request. + + + +The top item in the `private_call_requests` of the [`previous_kernel`](#previouskernel) must pertain to the current function call. + +This circuit will: + +1. Pop the request from the stack: + + - `call_request = previous_kernel.public_inputs.transient_accumulated_data.private_call_requests.pop()` + +2. Compare the hash with that of the current function call: + + - `call_request.call_stack_item_hash == private_call.call_stack_item.hash()` + - The hash of the `call_stack_item` is computed as: + - `hash(contract_address, function_data.hash(), public_inputs.hash(), counter_start, counter_end)` + - Where `function_data.hash()` and `public_inputs.hash()` are the hashes of the serialized field elements. + +#### Ensuring this function is called with the correct context. + +For the `call_context` in the [`public_inputs`](./private-function.md#public-inputs) of the [`private_call`](#privatecall)[`.call_stack_item`](./private-kernel-initial.mdx#privatecallstackitem) and the `call_request` popped in the [previous step](#ensuring-the-current-call-matches-the-call-request), this circuit checks that: + +1. If it is a standard call: `call_context.is_delegate_call == false` + + - The `msg_sender` of the current iteration must be the same as the caller's `contract_address`: + - `call_context.msg_sender == call_request.caller_contract_address` + - The `storage_contract_address` of the current iteration must be the same as its `contract_address`: + - `call_context.storage_contract_address == call_stack_item.contract_address` + +2. If it is a delegate call: `call_context.is_delegate_call == true` + + - The `caller_context` in the `call_request` must not be empty. Specifically, the following values of the caller must not be zeros: + - `msg_sender` + - `storage_contract_address` + - The `msg_sender` of the current iteration must equal the caller's `msg_sender`: + - `call_context.msg_sender == caller_context.msg_sender` + - The `storage_contract_address` of the current iteration must equal the caller's `storage_contract_address`: + - `call_context.storage_contract_address == caller_context.storage_contract_address` + - The `storage_contract_address` of the current iteration must not equal the `contract_address`: + - `call_context.storage_contract_address != call_stack_item.contract_address` + +3. If it is NOT a static call: `call_context.is_static_call == false` + + - The previous iteration must not be a static call: + - `caller_context.is_static_call == false` + +4. If it is an internal call: `call_stack_item.function_data.is_internal == true` + + - The `msg_sender` of the current iteration must equal the `storage_contract_address`: + - `call_context.msg_sender == call_context.storage_contract_address` + +#### Verifying the private function proof. + +It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs, sourced from [`private_inputs`](#private-inputs)[`.private_call`](#privatecall). + +This circuit verifies this proof and [the proof of the previous kernel iteration](#verifying-the-previous-kernel-proof) using recursion, and generates a single proof. This consolidation of multiple proofs into one is what allows the private kernel circuits to gradually merge private function proofs into a single proof of execution that represents the entire private section of a transaction. + +#### Verifying the public inputs of the private function circuit. + +It ensures the private function circuit's intention by checking the following in [`private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs): + +- The `block_header` must match the one in the [constant_data](./private-kernel-initial.mdx#constantdata). +- If it is a static call (`public_inputs.call_context.is_static_call == true`), it ensures that the function does not induce any state changes by verifying that the following arrays are empty: + - `note_hashes` + - `nullifiers` + - `l2_to_l1_messages` + - `unencrypted_log_hashes` + - `encrypted_log_hashes` + - `encrypted_note_preimage_hashes` + +#### Verifying the counters. + +This section follows the same [process](./private-kernel-initial.mdx#verifying-the-counters) as outlined in the initial private kernel circuit. + +Additionally, it verifies that for the [`call_stack_item`](#privatecallstackitem), the `counter_start` and `counter_end` must match those in the `call_request` [popped](#ensuring-the-current-call-matches-the-call-request) from the `private_call_requests` in a previous step. + +### Validating Public Inputs + +#### Verifying the transient accumulated data. + +The [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) in this circuit's [`public_inputs`](#public-inputs) includes values from both the previous iterations and the [`private_call`](#privatecall). + +For each array in the `transient_accumulated_data`, this circuit verifies that: + +1. It is populated with the values from the previous iterations, specifically: + + - `public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]` + + > It's important to note that the top item in the `private_call_requests` from the `previous_kernel` won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). + +2. As for the subsequent items appended after the values from the previous iterations, they constitute the values from the `private_call`, and each must undergo the same [verification](./private-kernel-initial.mdx#verifying-the-transient-accumulated-data) as outlined in the initial private kernel circuit. + +#### Verifying the constant data. + +It verifies that the [`constant_data`](./private-kernel-initial.mdx#constantdata) in the [`public_inputs`](#public-inputs) matches the `constant_data` in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs). + + + +
+
+ + + +```mermaid +classDiagram +direction TB + +class PrivateInputs { + transaction_request: TransactionRequest + private_call: PrivateCall + previous_kernel: PreviousKernel +} +PrivateInputs *-- TransactionRequest: transaction_request +PrivateInputs *-- PrivateCall: private_call + +class TransactionRequest { + origin: AztecAddress + function_data: FunctionData + args_hash: field + tx_context: TransactionContext +} +TransactionRequest *-- FunctionData: function_data +TransactionRequest *-- TransactionContext: tx_context + +TransactionRequest ..> ConstantData: tx_context + +class PrivateCall { + call_stack_item: PrivateCallStackItem + proof: Proof + vk: VerificationKey + bytecode_hash: field + contract_data: ContractInstance + contract_class: ContractClass + function_leaf_membership_witness: MembershipWitness +} +PrivateCall *-- PrivateCallStackItem: call_stack_item +PrivateCall *-- Proof: proof +PrivateCall *-- VerificationKey: vk +PrivateCall *-- ContractInstance: contract_data +PrivateCall *-- ContractClass: contract_class +PrivateCall *-- MembershipWitness: function_leaf_membership_witness + +VerificationKey ..> FUNCTION_EXISTENCE_CHECK: Check vk exists within function leaf +FunctionData ..> FUNCTION_EXISTENCE_CHECK: Check function_data exists within function leaf +MembershipWitness ..> FUNCTION_EXISTENCE_CHECK: Check function leaf exists within \nprivate function tree + +FUNCTION_EXISTENCE_CHECK .. ContractClass: computed_root == private_functions + +VerificationKey ..> PROOF_VERIFICATION +Proof ..> PROOF_VERIFICATION +PrivateFunctionPublicInputs ..> PROOF_VERIFICATION + +ContractClass .. ContractInstance: hash(contract_class) == contract_class_id + +class ContractClass { + version: u8 + registerer_address: AztecAddress + artifact_hash: field + private_functions: field + public_functions: field + unconstrained_functions: field +} + +class TransactionContext { + tx_type: standard|fee_paying|fee_rebate + chain_id: field + version: field +} + +class PrivateCallStackItem { + contract_address: AztecAddress + function_data: FunctionData + public_inputs: PrivateFunctionPublicInputs + counter_start: field + counter_end: field +} +PrivateCallStackItem *-- FunctionData: function_data +PrivateCallStackItem *-- PrivateFunctionPublicInputs: public_inputs + +PrivateCallStackItem .. TransactionRequest: function_data==function_data + + +PrivateCallStackItem .. CallContext: if is_delegatecall then\n contract_address == msg_sender \nelse \n contract_address == storage_contract_address + +PrivateCallStackItem .. PrivateFunctionPublicInputs: Validate counter_start & counter_end\nvs. the counters of the ordered arrays + +PrivateCallStackItem .. CallRequest: Validate all counter_start\n& counter_end values. + +TransactionRequest .. PrivateFunctionPublicInputs: args_hash == args_hash + +TransactionRequest .. CallContext: origin == msg_sender + +ContractInstance .. PrivateCallStackItem: hash(contract_data) == contract_address + +class FunctionData { + function_selector: u32 + function_type: private|public|unconstrained + is_internal: bool +} + +class PrivateFunctionPublicInputs { + call_context: CallContext + args_hash: field + return_values: List~field~ + note_hashes: List~NoteHash~ + nullifiers: List~Nullifier~ + l2_to_l1_messages: List~field~ + read_requests: List~ReadRequest~ + nullifier_key_validation_requests: List~NullifierKeyValidationRequest~ + unencrypted_log_hashes: List~UnencryptedLogHash~ + encrypted_log_hashes: List~EncryptedLogHash~ + encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ + private_call_stack_item_hashes: List~field~ + public_call_stack_item_hashes: List~field~ + block_header: BlockHeader + chain_id: field + version: field +} +PrivateFunctionPublicInputs *-- CallContext: call_context +PrivateFunctionPublicInputs *-- NoteHash: note_hashes +PrivateFunctionPublicInputs *-- Nullifier: nullifiers +PrivateFunctionPublicInputs *-- ReadRequest: read_requests +PrivateFunctionPublicInputs *-- NullifierKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes +PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes +PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes +PrivateFunctionPublicInputs *-- BlockHeader: block_header + +TransactionContext .. PrivateFunctionPublicInputs: chain_id==chain_id\nversion==version + +class FUNCTION_EXISTENCE_CHECK { + Check the vk, function_data, + exist within the private function tree root +} +class PROOF_VERIFICATION { + Verify the proof +} + + +class CallContext { + msg_sender: AztecAddress + storage_contract_address: AztecAddress + portal_contract_address: AztecAddress + is_delegate_call: bool + is_static_call: bool +} +CallContext ..> CallerContext : call_context + +CallContext .. NoteHashContext: storage_contract_address\n== contract_address +CallContext .. NullifierContext: storage_contract_address\n== contract_address +CallContext .. ReadRequestContext: storage_contract_address\n== contract_address +CallContext .. NullifierKeyValidationRequestContext: storage_contract_address\n== contract_address +CallContext .. UnencryptedLogHashContext: storage_contract_address\n== contract_address +CallContext .. EncryptedLogHashContext: storage_contract_address\n== contract_address +CallContext .. EncryptedNotePreimageHashContext: storage_contract_address\n== contract_address + + +PrivateFunctionPublicInputs ..> L2ToL1MessageContext: l2_to_l1_messages\n->l2_to_l1_message_contexts + +class NoteHash { + value: field + counter: field +} +NoteHash ..> NoteHashContext: note_hashes\n->note_hash_contexts + +class Nullifier { + value: field + counter: field + note_hash_counter: field +} +Nullifier ..> NullifierContext: nullifiers\n->nullifier_contexts + +class ReadRequest { + note_hash: field + counter: field +} +ReadRequest ..> ReadRequestContext: read_requests\n->read_request_contexts + +class NullifierKeyValidationRequest { + public_key: GrumpkinPoint + secret_key: fq +} +NullifierKeyValidationRequest ..> NullifierKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts + +class UnencryptedLogHash { + hash: field + length: field + counter: field +} +UnencryptedLogHash ..> UnencryptedLogHashContext: unencrypted_log_hashes\n->unencrypted_log_hash_contexts + +class EncryptedLogHash { + hash: field + length: field + counter: field + randomness: field +} +EncryptedLogHash ..> EncryptedLogHashContext: encrypted_log_hashes\n->encrypted_log_hash_contexts + +class EncryptedNotePreimageHash { + hash: field + length: field + counter: field + note_hash_counter: field +} +EncryptedNotePreimageHash ..> EncryptedNotePreimageHashContext: encrypted_note_preimage_hashes\n->encrypted_note_preimage_hash_contexts + + +class BlockHeader { + note_hash_tree_root: field + nullifier_tree_root: field + l1_to_l2_message_tree_root: field + public_data_tree_root: field + archive_tree_root: field + global_variables_hash: field +} + +class CallRequest { + call_stack_item_hash: field + caller_contract: AztecAddress + caller_context: CallerContext + counter_start: field + counter_end: field +} +CallerContext --* CallRequest : caller_context + +PrivateFunctionPublicInputs ..> CallRequest: private_call_stack_item_hash->call_stack_item_hash\npublic_call_stack_item_hash->call_stack_item_hash + +class CallerContext { + msg_sender: AztecAddress + storage_contract_address: AztecAddress + is_static_call: bool +} + + + +class NoteHashContext { + value: field + counter: field + nullifier_counter: field + contract_address: AztecAddress +} + +class NullifierContext { + value: field + counter: field + note_hash_counter: field + contract_address: AztecAddress +} + +class L2ToL1MessageContext { + value: field + portal_contract_address: AztecAddress + contract_address: AztecAddress +} + +class ReadRequestContext { + note_hash: field + counter: field + contract_address: AztecAddress +} + +class NullifierKeyValidationRequestContext { + public_key: field + secret_key: field + contract_address: AztecAddress +} + +class UnencryptedLogHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress +} + +class EncryptedLogHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress + randomness: field +} + +class EncryptedNotePreimageHashContext { + hash: field + length: field + counter: field + contract_address: AztecAddress + note_hash_counter: field +} + +class MembershipWitness { + leaf_index: field + sibling_path: List~field~ +} + +class ContractInstance { + version: u8 + deployer_address: AztecAddress + salt: field + contract_class_id: field + contract_args_hash: field + portal_contract_address: EthereumAddress + public_keys_hash: Field +} + +class TransientAccumulatedData { + note_hash_contexts: List~NoteHashContext~ + nullifier_contexts: List~NullifierContext~ + l2_to_l1_message_contexts: List~L2ToL1MessageContext~ + read_request_contexts: List~ReadRequestContext~ + nullifier_key_validation_request_contexts: List~NullifierKeyValidationRequestContext~ + unencrypted_log_hash_contexts: List~UnencryptedLogHashContext~ + encrypted_log_hash_contexts: List~EncryptedLogHashContext~ + encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ + private_call_requests: List~CallRequest~ + public_call_requests: List~CallRequest~ +} +NoteHashContext --* TransientAccumulatedData: note_hash_contexts +NullifierContext --* TransientAccumulatedData: nullifier_contexts +L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts +ReadRequestContext --* TransientAccumulatedData: read_request_contexts +NullifierKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts +EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts +EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts +CallRequest --* TransientAccumulatedData: private_call_requests +CallRequest --* TransientAccumulatedData: public_call_requests + +class ConstantData { + block_header: BlockHeader + tx_context: TransactionContext +} +BlockHeader ..> ConstantData: block_header + +class PublicInputs { + constant_data: ConstantData + transient_accumulated_data: TransientAccumulatedData +} +ConstantData --* PublicInputs : constant_data +TransientAccumulatedData --* PublicInputs: transient_accumulated_data + + + + + +%%========================================================================================================================================================= +%% EVERYTHING ABOVE THIS LINE SHOULD BE COPY-PASTED FROM THE DIAGRAM IN ../private-kernel-initial.mdx +%% EVERYTHING BELOW THIS LINE NEEDS TO BE EDITED IN LINE WITH PROTOCOL CHANGES. +%%========================================================================================================================================================= + + + + + + +%% You'll also need to modify the PrivateInputs class (way above) to include an extra item: `previous_kernel: PreviousKernel` + +PrivateInputs *.. PreviousKernel: previous_kernel + +class PreviousKernel { + public_inputs: PrivateKernelPublicInputs + proof: KernelProof (aka Proof) + vk: KernelVerificationKey (aka VerificationKey) + membership_witness: KernelVKMembershipWitness (aka MembershipWitness) +} +PreviousKernel *-- PrivateKernelPublicInputs: public_inputs\n(the same PublicInputs type \n as the public_inputs \n being output by this circuit) +PreviousKernel *-- KernelProof: proof +PreviousKernel *-- KernelVerificationKey: vk +PreviousKernel *-- KernelVKMembershipWitness: membership_witness +PreviousKernel *-- PublicInputs: public_inputs\nBEWARE, this line is just showing class\ndependency and the recursive nature of this circuit.\nThe "output" public_inputs of the PREVIOUS kernel iteration\n are "fed" as inputs into this kernel iteration. + +class KERNEL_VK_EXISTENCE_CHECK { + Check the vk + exists within the vk tree root +} +class KERNEL_PROOF_VERIFICATION { + Verify the kernel proof +} +KernelProof ..> KERNEL_PROOF_VERIFICATION +KernelVerificationKey ..> KERNEL_PROOF_VERIFICATION +PrivateKernelPublicInputs ..> KERNEL_PROOF_VERIFICATION + +KernelVerificationKey ..> KERNEL_VK_EXISTENCE_CHECK +KernelVKMembershipWitness ..> KERNEL_VK_EXISTENCE_CHECK + + +``` + +
+
+ +## Private Inputs + +### `PreviousKernel` + +Data of the previous kernel iteration. + + + + +| Field | Type | Description | +| -------------------- | ------------------------------------------------------------------------------- | -------------------------------------------- | +| `public_inputs` | [`InitialPrivateKernelPublicInputs`](./private-kernel-initial.mdx#publicinputs) | Public inputs of the proof. | +| `proof` | `Proof` | Proof of the kernel circuit. | +| `vk` | `VerificationKey` | Verification key of the kernel circuit. | +| `membership_witness` | [`MembershipWitness`](./private-kernel-initial.mdx#membershipwitness) | Membership witness for the verification key. | + +### `PrivateCall` + +The format aligns with the [`PrivateCall`](./private-kernel-initial.mdx#privatecall) of the initial private kernel circuit. + +## `PublicInputs` + +The format aligns with the [`Public Inputs`](./private-kernel-initial.mdx#publicinputs) of the initial private kernel circuit. diff --git a/yellow-paper/docs/circuits/private-kernel-reset.md b/yellow-paper/docs/circuits/private-kernel-reset.md index a5c6bff1cae..a9c4feb7b5f 100644 --- a/yellow-paper/docs/circuits/private-kernel-reset.md +++ b/yellow-paper/docs/circuits/private-kernel-reset.md @@ -1,159 +1,168 @@ # Private Kernel Circuit - Reset + + + + ## Requirements A **reset** circuit is designed to abstain from processing individual private function calls. Instead, it injects the outcomes of an initial, inner, or another reset private kernel circuit, scrutinizes the public inputs, and clears the verifiable data within its scope. A reset circuit can be executed either preceding the tail private kernel circuit, or as a means to "reset" public inputs at any point between two private kernels, allowing data to accumulate seamlessly in subsequent iterations. There are 2 variations of reset circuits: + + + - [Read Request Reset Private Kernel Circuit](#read-request-reset-private-kernel-circuit). -- [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit). +- [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit). - [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit). The incorporation of these circuits not only enhances the modularity and repeatability of the "reset" process but also diminishes the overall workload. Rather than conducting resource-intensive computations such as membership checks in each iteration, these tasks are only performed as necessary within the reset circuits. ### Read Request Reset Private Kernel Circuit. -This reset circuit conducts verification on some or all accumulated read requests and subsequently removes them from the _read_request_contexts_ in the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ within the _public_inputs_ of the [_previous_kernel_](#previouskernel). + + +This reset circuit conducts verification on some or all accumulated read requests and subsequently removes them from the [`read_request_contexts`](./private-kernel-initial.mdx/#readrequestcontext) in the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the [`public_inputs`](./private-kernel-initial.mdx#publicinputs) of the [`previous_kernel`](#previouskernel). A read request can pertain to one of two note types: - A settled note: generated in a prior successful transaction and included in the note hash tree. - A pending note: created in the current transaction, not yet part of the note hash tree. -1. To clear read requests for settled notes, the circuit performs membership checks for the targeted read requests using the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via _private_inputs_. +1. To clear read requests for settled notes, the circuit performs membership checks for the targeted read requests using the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs`. - For each _persistent_read_index_ at index _i_ in _persistent_read_indices_: + For each `persistent_read_index` at index `i` in `persistent_read_indices`: - 1. If the _persistent_read_index_ equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. - 2. Locate the _read_request_: _`read_request_contexts[persistent_read_index]`_ + 1. If the `persistent_read_index` equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. + 2. Locate the `read_request`: `read_request_contexts[persistent_read_index]` 3. Perform a membership check on the note being read. Where: - - The leaf corresponds to the hash of the note: _`read_request.note_hash`_ - - The index and sibling path are in: _`read_request_membership_witnesses[i]`_. - - The root is the _note_hash_tree_root_ in the _[header](./private-function.md#header)_ within _[public_inputs](#public-inputs).[constant_data](./private-kernel-initial.md#constantdata)_. + - The leaf corresponds to the hash of the note: `read_request.note_hash` + - The index and sibling path are in: `read_request_membership_witnesses[i]`. + - The root is the `note_hash_tree_root` in the [block_header](./private-function.md#header) within [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata). - > Following the above process, at most _N_ read requests will be cleared, where _N_ is the length of the _persistent_read_indices_ array. It's worth noting that there can be multiple versions of this reset circuit, each with a different value of _N_. + > Following the above process, at most `N` read requests will be cleared, where `N` is the length of the `persistent_read_indices` array. It's worth noting that there can be multiple versions of this reset circuit, each with a different value of `N`. -2. To clear read requests for pending notes, the circuit ensures that the notes were created before the corresponding read operation, utilizing the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via _private_inputs_ +2. To clear read requests for pending notes, the circuit ensures that the notes were created before the corresponding read operation, utilizing the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs` - For each _transient_read_index_ at index _i_ in _transient_read_indices_: + For each `transient_read_index` at index `i` in `transient_read_indices`: - 1. If the _transient_read_index_ equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. - 2. Locate the _read_request_: _`read_request_contexts[transient_read_index]`_ - 3. Locate the _note_hash_ being read: _`note_hash_contexts[pending_note_indices[i]]`_ + 1. If the `transient_read_index` equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. + 2. Locate the `read_request`: `read_request_contexts[transient_read_index]` + 3. Locate the `note_hash` being read: `note_hash_contexts[pending_note_indices[i]]` 4. Verify the following: - - _`read_request.note_hash == note_hash.value`_ - - _`read_request.contract_address == note_hash.contract_address`_ - - _`read_request.counter > note_hash.counter`_ - - _`(read_request.counter < note_hash.nullifier_counter) | (note_hash.nullifier_counter == 0)`_ + - `read_request.note_hash == note_hash.value` + - `read_request.contract_address == note_hash.contract_address` + - `read_request.counter > note_hash.counter` + - `(read_request.counter < note_hash.nullifier_counter) | (note_hash.nullifier_counter == 0)` - > Given that a reset circuit can execute between two private kernel circuits, there's a possibility that a note is created in a nested execution and hasn't been added to the _public_inputs_. In such cases, the read request cannot be verified in the current reset circuit and must be processed in another reset circuit after the note has been included in the _public_inputs_. + > Given that a reset circuit can execute between two private kernel circuits, there's a possibility that a note is created in a nested execution and hasn't been added to the `public_inputs`. In such cases, the read request cannot be verified in the current reset circuit and must be processed in another reset circuit after the note has been included in the `public_inputs`. -3. This circuit then ensures that the read requests that haven't been verified should remain in the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ within its _public_inputs_. +3. This circuit then ensures that the read requests that haven't been verified should remain in the [transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata) within its `public_inputs`. - For each _read_request_ at index _i_ in the _read_request_contexts_ within the _private_inputs_, find its _status_ at _`read_request_statuses[i]`_: + For each `read_request` at index `i` in the `read_request_contexts` within the `private_inputs`, find its `status` at `read_request_statuses[i]`: - - If _status.state == persistent_, _`i == persistent_read_indices[status.index]`_. - - If _status.state == transient_, _`i == transient_read_indices[status.index]`_. - - If _status.state == nada_, _`read_request == public_inputs.transient_accumulated_data.read_request_contexts[status.index]`_. + - If `status.state == persistent`, `i == persistent_read_indices[status.index]`. + - If `status.state == transient`, `i == transient_read_indices[status.index]`. + - If `status.state == nada`, `read_request == public_inputs.transient_accumulated_data.read_request_contexts[status.index]`. ### Nullifier Key Validation Request Reset Private Kernel Circuit. -This reset circuit validates the correct derivation of nullifier secret keys used in private functions, and subsequently removes them from the _nullifier_key_validation_request_contexts_ in the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ within the _public_inputs_ of the [_previous_kernel_](#previouskernel). +This reset circuit validates the correct derivation of nullifier secret keys used in private functions, and subsequently removes them from the `nullifier_key_validation_request_contexts` in the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the `public_inputs` of the [`previous_kernel`](#previouskernel). -Initialize _requests_kept_ to _0_. +Initialize `requests_kept` to `0`. -For each _request_ at index _i_ in _nullifier_key_validation_request_contexts_, locate the _master_secret_key_ at _`master_nullifier_secret_keys[i]`_, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through _private_inputs_. +For each `request` at index `i` in `nullifier_key_validation_request_contexts`, locate the `master_secret_key` at `master_nullifier_secret_keys[i]`, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through `private_inputs`. -1. If _`master_secret_key == 0`_, ensure the request remain within the _public_inputs_.: +1. If `master_secret_key == 0`, ensure the request remain within the `public_inputs`.: - - _`public_inputs.transient_accumulated_data.nullifier_key_validation_request_contexts[requests_kept] == request`_ - - Increase _requests_kept_ by _1_: _`requests_kept += 1`_ + - `public_inputs.transient_accumulated_data.nullifier_key_validation_request_contexts[requests_kept] == request` + - Increase `requests_kept` by 1: `requests_kept += 1` 2. Else: - - Verify that the public key is associated with the _master_secret_key_: - _`request.public_key == master_secret_key * G`_ + - Verify that the public key is associated with the `master_secret_key`: + `request.public_key == master_secret_key * G` - Verify that the secret key was correctly derived for the contract: - _`request.secret_key == hash(master_secret_key, request.contract_address)`_ + `request.secret_key == hash(master_secret_key, request.contract_address)` ### Transient Note Reset Private Kernel Circuit. In the event that a pending note is nullified within the same transaction, its note hash, nullifier, and all encrypted note preimage hashes can be removed from the public inputs. This not only avoids redundant data being broadcasted, but also frees up space for additional note hashes and nullifiers in the subsequent iterations. -1. Ensure that each note hash is either propagated to the _public_inputs_ or nullified in the same transaction. +1. Ensure that each note hash is either propagated to the `public_inputs` or nullified in the same transaction. - Initialize both _notes_kept_ and _notes_removed_ to _0_. + Initialize both `notes_kept` and `notes_removed` to `0`. - For each _note_hash_ at index _i_ in _note_hash_contexts_ within the _private_inputs_, find the index of its nullifer at _`transient_nullifier_indices[i]`_, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): + For each `note_hash` at index `i` in `note_hash_contexts` within the `private_inputs`, find the index of its nullifer at `transient_nullifier_indices[i]`, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): - - If _`transient_nullifier_indices[i] == nullifier_contexts.len()`_: - - Verify that the _note_hash_ remains within the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ in the _public_inputs_: - _`note_hash == public_inputs.transient_accumulated_data.note_hash_contexts[notes_kept]`_ - - Increment _notes_kept_ by 1: _`notes_kept += 1`_ - - Else, locate the _nullifier_ at _`nullifier_contexts[transient_nullifier_indices[i]]`_: + - If `transient_nullifier_indices[i] == nullifier_contexts.len()`: + - Verify that the `note_hash` remains within the [transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata) in the `public_inputs`: + `note_hash == public_inputs.transient_accumulated_data.note_hash_contexts[notes_kept]` + - Increment `notes_kept` by 1: `notes_kept += 1` + - Else, locate the `nullifier` at `nullifier_contexts[transient_nullifier_indices[i]]`: - Verify that the nullifier is associated with the note: - - _`nullifier.contract_address == note_hash.contract_address`_ - - _`nullifier.note_hash_counter == note_hash.counter`_ - - _`nullifier.counter == note_hash.nullifier_counter`_ - - Increment _notes_removed_ by 1: _`notes_removed += 1`_ - - Ensure that an empty _note_hash_ is appended to the end of _note_hash_contexts_ in the _public_inputs_: - - _`public_inputs.transient_accumulated_data.note_hash_contexts[N - notes_removed].is_empty() == true`_ - - Where _N_ is the length of _note_hash_contexts_. + - `nullifier.contract_address == note_hash.contract_address` + - `nullifier.note_hash_counter == note_hash.counter` + - `nullifier.counter == note_hash.nullifier_counter` + - Increment `notes_removed` by 1: `notes_removed += 1` + - Ensure that an empty `note_hash` is appended to the end of `note_hash_contexts` in the `public_inputs`: + - `public_inputs.transient_accumulated_data.note_hash_contexts[N - notes_removed].is_empty() == true` + - Where `N` is the length of `note_hash_contexts`. - > Note that the check `nullifier.counter > note_hash.counter` is not necessary as the _nullifier_counter_ is assured to be greater than the counter of the note hash when [propagated](./private-kernel-initial.md#verifying-the-transient-accumulated-data) from either the initial or inner private kernel circuits. + > Note that the check `nullifier.counter > note_hash.counter` is not necessary as the `nullifier_counter` is assured to be greater than the counter of the note hash when [propagated](./private-kernel-initial.mdx#verifying-the-transient-accumulated-data) from either the initial or inner private kernel circuits. -2. Ensure that nullifiers not associated with note hashes removed in the previous step are retained within the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ in the _public_inputs_. +2. Ensure that nullifiers not associated with note hashes removed in the previous step are retained within the [transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata) in the `public_inputs`. - Initialize both _nullifiers_kept_ and _nullifiers_removed_ to _0_. + Initialize both `nullifiers_kept` and `nullifiers_removed` to `0`. - For each _nullifier_ at index _i_ in the _nullifier_contexts_ within the _private_inputs_, find the index of its corresponding transient nullifier at _`nullifier_index_hints[i]`_, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): + For each `nullifier` at index `i` in the `nullifier_contexts` within the `private_inputs`, find the index of its corresponding transient nullifier at `nullifier_index_hints[i]`, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): - - If _`nullifier_index_hints[i] == transient_nullifier_indices.len()`_: - - Verify that the _nullifier_ remains within the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ in the _public_inputs_: - _`nullifier == public_inputs.transient_accumulated_data.nullifier_contexts[nullifiers_kept]`_ - - Increment _nullifiers_kept_ by 1: _`nullifiers_kept += 1`_ - - Else, compute _transient_nullifier_index_ as _`transient_nullifier_indices[nullifier_index_hints[i]]`_: - - Verify that: _`transient_nullifier_index == i`_ - - Increment _nullifiers_removed_ by 1: _`nullifiers_removed += 1`_ - - Ensure that an empty _nullifier_ is appended to the end of _nullifier_contexts_ in the _public_inputs_: - - _`public_inputs.transient_accumulated_data.nullifier_contexts[N - nullifiers_removed].is_empty() == true`_ - - Where _N_ is the length of _nullifer_contexts_. + - If `nullifier_index_hints[i] == transient_nullifier_indices.len()`: + - Verify that the `nullifier` remains within the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) in the `public_inputs`: + `nullifier == public_inputs.transient_accumulated_data.nullifier_contexts[nullifiers_kept]` + - Increment `nullifiers_kept` by 1: `nullifiers_kept += 1` + - Else, compute `transient_nullifier_index` as `transient_nullifier_indices[nullifier_index_hints[i]]`: + - Verify that: `transient_nullifier_index == i` + - Increment `nullifiers_removed` by 1: `nullifiers_removed += 1` + - Ensure that an empty `nullifier` is appended to the end of `nullifier_contexts` in the `public_inputs`: + - `public_inputs.transient_accumulated_data.nullifier_contexts[N - nullifiers_removed].is_empty() == true` + - Where `N` is the length of `nullifer_contexts`. After these steps, ensure that all nullifiers associated with transient note hashes have been identified and removed: - _`nullifiers_removed == notes_removed`_ + `nullifiers_removed == notes_removed` -3. Ensure that _encrypted_note_preimage_hashes_ not associated with note hashes removed in the previous step are retained within the _[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ in the _public_inputs_. +3. Ensure that `encrypted_note_preimage_hashes` not associated with note hashes removed in the previous step are retained within the `[transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata)` in the `public_inputs`. - Initialize both _hashes_kept_ and _hashes_removed_ to _0_. + Initialize both `hashes_kept` and `hashes_removed` to `0`. - For each _preimage_hash_ at index _i_ in the _encrypted_note_preimage_hash_contexts_ within the _private_inputs_, find the _index_hint_ of its corresponding hash within _public_inputs_ at _`encrypted_note_preimage_hash_index_hints[i]`_, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): + For each `preimage_hash` at index `i` in the `encrypted_note_preimage_hash_contexts` within the `private_inputs`, find the `index_hint` of its corresponding hash within `public_inputs` at `encrypted_note_preimage_hash_index_hints[i]`, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): - - If _`index_hint == encrypted_note_preimage_hash_contexts.len()`_: + - If `index_hint == encrypted_note_preimage_hash_contexts.len()`: - Ensure that the associated note hash is removed: - - Locate the _note_hash_ at _`private_inputs.transient_accumulated_data.note_hash_contexts[log_note_hash_hints[i]]`_. - - Verify that the _preimage_hash_ is associated with the _note_hash_: - - _`preimage_hash.note_hash_counter == note_hash.counter`_ - - _`preimage_hash.contract_address == note_hash.contract_address`_ - - Confirm that the _note_hash_ has a corresponding nullifier and has been removed in the first step of this section: - - _`transient_nullifier_indices[log_note_hash_hints[i]] != nullifier_contexts.len()`_ - - Increment _hashes_removed_ by 1: _`hashes_removed += 1`_ - - Ensure that an empty item is appended to the end of _encrypted_note_preimage_hash_contexts_ in the _public_inputs_: - - _`encrypted_note_preimage_hash_contexts[N - hashes_removed].is_empty() == true`_ - - Where _N_ is the length of _encrypted_note_preimage_hash_contexts_. - - Else, find the _mapped_preimage_hash_ at _`encrypted_note_preimage_hash_contexts[index_hint]`_ within _public_inputs_: - - Verify that the context is aggregated to the _public_inputs_ correctly: - - _`index_hint == hashes_kept`_ - - _`mapped_preimage_hash == preimage_hash`_ - - Ensure that the associated note hash is retained in the _public_inputs_: - - Locate the _note_hash_ at _`public_inputs.transient_accumulated_data.note_hash_contexts[log_note_hash_hints[i]]`_. - - Verify that the _preimage_hash_ is associated with the _note_hash_: - - _`preimage_hash.note_hash_counter == note_hash.counter`_ - - _`preimage_hash.contract_address == note_hash.contract_address`_ - - Increment _hashes_kept_ by 1: _`hashes_kept += 1`_ - -> Note that this reset process may not necessarily be applied to all transient notes at a time. In cases where a note will be read in a yet-to-be-processed nested execution, the transient note hash and its nullifier must be retained in the _public_inputs_. The reset can only occur in a later reset circuit after all associated read requests have been verified and cleared. + - Locate the `note_hash` at `private_inputs.transient_accumulated_data.note_hash_contexts[log_note_hash_hints[i]]`. + - Verify that the `preimage_hash` is associated with the `note_hash`: + - `preimage_hash.note_hash_counter == note_hash.counter` + - `preimage_hash.contract_address == note_hash.contract_address` + - Confirm that the `note_hash` has a corresponding nullifier and has been removed in the first step of this section: + - `transient_nullifier_indices[log_note_hash_hints[i]] != nullifier_contexts.len()` + - Increment `hashes_removed` by 1: `hashes_removed += 1` + - Ensure that an empty item is appended to the end of `encrypted_note_preimage_hash_contexts` in the `public_inputs`: + - `encrypted_note_preimage_hash_contexts[N - hashes_removed].is_empty() == true` + - Where `N` is the length of `encrypted_note_preimage_hash_contexts`. + - Else, find the `mapped_preimage_hash` at `encrypted_note_preimage_hash_contexts[index_hint]` within `public_inputs`: + - Verify that the context is aggregated to the `public_inputs` correctly: + - `index_hint == hashes_kept` + - `mapped_preimage_hash == preimage_hash` + - Ensure that the associated note hash is retained in the `public_inputs`: + - Locate the `note_hash` at `public_inputs.transient_accumulated_data.note_hash_contexts[log_note_hash_hints[i]]`. + - Verify that the `preimage_hash` is associated with the `note_hash`: + - `preimage_hash.note_hash_counter == note_hash.counter` + - `preimage_hash.contract_address == note_hash.contract_address` + - Increment `hashes_kept` by 1: `hashes_kept += 1` + +> Note that this reset process may not necessarily be applied to all transient notes at a time. In cases where a note will be read in a yet-to-be-processed nested execution, the transient note hash and its nullifier must be retained in the `public_inputs`. The reset can only occur in a later reset circuit after all associated read requests have been verified and cleared. ### Common Verifications @@ -161,79 +170,79 @@ Below are the verifications applicable to all reset circuits: #### Verifying the previous kernel proof. -It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. +It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from [private_inputs](#private-inputs).[previous_kernel](#previouskernel). The preceding proof can be: -- [Initial private kernel proof](./private-kernel-initial.md). -- [Inner private kernel proof](./private-kernel-inner.md). +- [Initial private kernel proof](./private-kernel-initial.mdx). +- [Inner private kernel proof](./private-kernel-inner.mdx). - Reset private kernel proof. #### Verifying the accumulated data. -It ensures that the _accumulated_data_ in the _[public_inputs](#public-inputs)_ matches the _accumulated_data_ in _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.md#public-inputs)_. +It ensures that the `accumulated_data` in the `[public_inputs](#public-inputs)` matches the `accumulated_data` in [private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.mdx#public-inputs). #### Verifying the transient accumulated data. -The following must equal the corresponding arrays in _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.md#public-inputs).[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_: +The following must equal the corresponding arrays in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata): -- _l2_to_l1_message_contexts_ -- _private_call_requests_ -- _public_call_requests_ +- `l2_to_l1_message_contexts` +- `private_call_requests` +- `public_call_requests` The following must remain the same for [read request reset private kernel circuit](#read-request-reset-private-kernel-circuit): -- _note_hash_contexts_ -- _nullifier_contexts_ +- `note_hash_contexts` +- `nullifier_contexts` The following must remain the same for [transient note reset private kernel circuit](#transient-note-reset-private-kernel-circuit): -- _read_request_contexts_ +- `read_request_contexts` #### Verifying the constant data. -This section follows the same [process](./private-kernel-inner.md#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. -## Private Inputs +## `PrivateInputs` -### _PreviousKernel_ +### `PreviousKernel` -The format aligns with the _[PreviousKernel](./private-kernel-inner.md#previouskernel)_ of the inner private kernel circuit. +The format aligns with the [`PreviousKernel`](./private-kernel-inner.mdx#previouskernel) of the inner private kernel circuit. ### _Hints_ for [Read Request Reset Private Kernel Circuit](#read-request-reset-private-kernel-circuit) -| Field | Type | Description | -| ----------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -| _transient_read_indices_ | [_field_; _N_] | Indices of the read requests for transient notes. | -| _pending_note_indices_ | [_field_; _N_] | Indices of the note hash contexts for transient reads. | -| _persistent_read_indices_ | [_field_; _M_] | Indices of the read requests for settled notes. | -| _read_request_membership_witnesses_ | [_[MembershipWitness](./private-kernel-initial.md#membershipwitness)_; _M_] | Membership witnesses for the persistent reads. | -| _read_request_statuses_ | [_[ReadRequestStatus](#readrequeststatus)_; _C_] | Statuses of the read request contexts. _C_ equals the length of _read_request_contexts_. | +| Field | Type | Description | +| ----------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | +| `transient_read_indices` | `[field; N]` | Indices of the read requests for transient notes. | +| `pending_note_indices` | `[field; N]` | Indices of the note hash contexts for transient reads. | +| `persistent_read_indices` | `[field; M]` | Indices of the read requests for settled notes. | +| `read_request_membership_witnesses` | [`[MembershipWitness; M]`](./private-kernel-initial.mdx#membershipwitness) | Membership witnesses for the persistent reads. | +| `read_request_statuses` | [`[ReadRequestStatus; C]`](#readrequeststatus) | Statuses of the read request contexts. `C` equals the length of `read_request_contexts`. | -> There can be multiple versions of the read request reset private kernel circuit, each with a different values of _N_ and _M_. +> There can be multiple versions of the read request reset private kernel circuit, each with a different values of `N` and `M`. -#### _ReadRequestStatus_ +#### `ReadRequestStatus` -| Field | Type | Description | -| ------- | ------------------------------- | --------------------------------------- | -| _state_ | persistent \| transient \| nada | State of the read request. | -| _index_ | _field_ | Index of the hint for the read request. | +| Field | Type | Description | +| ------- | --------------------------------- | --------------------------------------- | +| `state` | `persistent \| transient \| nada` | State of the read request. | +| `index` | `field` | Index of the hint for the read request. | ### _Hints_ for [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) -| Field | Type | Description | -| ------------------------------ | -------------- | -------------------------------------------------------------------------------------------------------------------------- | -| _master_nullifier_secret_keys_ | [_field_; _C_] | Master nullifier secret keys for the nullifier keys. _C_ equals the length of _nullifier_key_validation_request_contexts_. | +| Field | Type | Description | +| ------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------- | +| `master_nullifier_secret_keys` | `[field; C]` | Master nullifier secret keys for the nullifier keys. `C` equals the length of `nullifier_key_validation_request_contexts`. | ### _Hints_ for [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit) -| Field | Type | Description | -| ------------------------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| _transient_nullifier_indices_ | [_field_; _C_] | Indices of the nullifiers for transient notes. _C_ equals the length of _note_hash_contexts_. | -| _nullifier_index_hints_ | [_field_; _C_] | Indices of the _transient_nullifier_indices_ for transient nullifiers. _C_ equals the length of _nullifier_contexts_. | -| _encrypted_note_preimage_hash_index_hints_ | [_field_; _C_] | Indices of the _encrypted_note_preimage_hash_contexts_ for transient preimage hashes. _C_ equals the length of _encrypted_note_preimage_hash_contexts_. | -| _log_note_hash_hints_ | [_field_; _C_] | Indices of the _note_hash_contexts_ for transient preimage hashes. _C_ equals the length of _note_hash_contexts_. | +| Field | Type | Description | +| ------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `transient_nullifier_indices` | `[field; C]` | Indices of the nullifiers for transient notes. `C` equals the length of `note_hash_contexts`. | +| `nullifier_index_hints` | `[field; C]` | Indices of the `transient_nullifier_indices` for transient nullifiers. `C` equals the length of `nullifier_contexts`. | +| `encrypted_note_preimage_hash_index_hints` | `[field; C]` | Indices of the `encrypted_note_preimage_hash_contexts` for transient preimage hashes. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | +| `log_note_hash_hints` | `[field; C]` | Indices of the `note_hash_contexts` for transient preimage hashes. `C` equals the length of `note_hash_contexts`. | -## Public Inputs +## `PublicInputs` -The format aligns with the _[Public Inputs](./private-kernel-initial.md#public-inputs)_ of the initial private kernel circuit. +The format aligns with the [`PublicInputs`](./private-kernel-initial.mdx#publicinputs) of the initial private kernel circuit. diff --git a/yellow-paper/docs/circuits/private-kernel-tail.md b/yellow-paper/docs/circuits/private-kernel-tail.md index 4f7b27cd676..cbfe8088a88 100644 --- a/yellow-paper/docs/circuits/private-kernel-tail.md +++ b/yellow-paper/docs/circuits/private-kernel-tail.md @@ -8,30 +8,30 @@ The **tail** circuit abstains from processing individual private function calls. #### Verifying the previous kernel proof. -It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. +It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel). The preceding proof can be: -- [Initial private kernel proof](./private-kernel-initial.md). -- [Inner private kernel proof](./private-kernel-inner.md). +- [Initial private kernel proof](./private-kernel-initial.mdx). +- [Inner private kernel proof](./private-kernel-inner.mdx). - [Reset private kernel proof](./private-kernel-reset.md). An inner iteration may be omitted when there's only a single private function call for the transaction. And a reset iteration can be skipped if there are no read requests and transient notes in the public inputs from the last iteration. #### Ensuring the previous iteration is the last. -It checks the data within _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.md#public-inputs).[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_ to ensure that no further private kernel iteration is needed. +It checks the data within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) to ensure that no further private kernel iteration is needed. 1. The following must be empty to ensure all the private function calls are processed: - - _private_call_requests_ + - `private_call_requests` 2. The following must be empty to ensure a comprehensive final reset: - - _read_requests_ - - _nullifier_key_validation_request_contexts_ - - The _nullifier_counter_ associated with each note hash in _note_hash_contexts_. - - The _note_hash_counter_ associated with each nullifier in _nullifier_contexts_. + - `read_requests` + - `nullifier_key_validation_request_contexts` + - The `nullifier_counter` associated with each note hash in `note_hash_contexts`. + - The `note_hash_counter` associated with each nullifier in `nullifier_contexts`. > A [reset iteration](./private-kernel-reset.md) should ideally precede this step. Although it doesn't have to be executed immediately before the tail circuit, as long as it effectively clears the specified values. @@ -41,52 +41,56 @@ It checks the data within _[private_inputs](#private-inputs).[previous_kernel](# Siloing a value with the address of the contract generating the value ensures that data produced by a contract is accurately attributed to the correct contract and cannot be misconstrued as data created in a different contract. This circuit guarantees the following siloed values: -1. Silo _nullifiers_: +1. Silo `nullifiers`: - For each _nullifier_ at index _i_ **> 0** in the _nullifier_contexts_ within _private_inputs_, if _`nullifier.value != 0`_: + For each `nullifier` at index `i > 0` in the `nullifier_contexts` within `private_inputs`, if `nullifier.value != 0`: - _`nullifier_contexts[i].value = hash(nullifier.contract_address, nullifier.value)`_ + `nullifier_contexts[i].value = hash(nullifier.contract_address, nullifier.value)` - > This process does not apply to _nullifier_contexts[0]_, which is the [hash of the transaction request](./private-kernel-initial.md#ensuring-transaction-uniqueness) created by the initial private kernel circuit. + > This process does not apply to `nullifier_contexts[0]`, which is the [hash of the transaction request](./private-kernel-initial.mdx#ensuring-transaction-uniqueness) created by the initial private kernel circuit. -2. Silo _note_hashes_: + - For each _note_hash_ at index _i_ in the _note_hash_contexts_ within _private_inputs_, if _`note_hash.value != 0`_: +2. Silo `note_hashes`: - _`note_hash_contexts[i].value = hash(nonce, siloed_hash)`_ + For each `note_hash` at index `i` in the `note_hash_contexts` within `private_inputs`, if `note_hash.value != 0`: + + `note_hash_contexts[i].value = hash(nonce, siloed_hash)` Where: - - _`nonce = hash(first_nullifier, index)`_ - - _`first_nullifier = nullifier_contexts[0].value`_. - - _`index = note_hash_hints[i]`_, which is the index of the same note hash within _public_inputs.note_hashes_. Where _note_hash_hints_ is provided as [hints](#hints) via _private_inputs_. - - _`siloed_hash = hash(note_hash.contract_address, note_hash.value)`_ + - `nonce = hash(first_nullifier, index)` + - `first_nullifier = nullifier_contexts[0].value`. + - `index = note_hash_hints[i]`, which is the index of the same note hash within `public_inputs.note_hashes`. Where `note_hash_hints` is provided as [hints](#hints) via `private_inputs`. + - `siloed_hash = hash(note_hash.contract_address, note_hash.value)` > Siloing with a nonce guarantees that each final note hash is a unique value in the note hash tree. -3. Verify the _l2_to_l1_messages_ within _[public_inputs](#public-inputs).[accumulated_data](./public-kernel-tail.md#accumulateddata)_: +3. Verify the `l2_to_l1_messages` within [`public_inputs`](#public-inputs)[`.accumulated_data`](./public-kernel-tail.md#accumulateddata): - For each _l2_to_l1_message_ at index _i_ in _l2_to_l1_message_contexts_ within _[private_inputs](#private-inputs).[previous_kernel](./private-kernel-inner.md#previouskernel).[public_inputs](./private-kernel-initial.md#private-inputs).[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_: + For each `l2_to_l1_message` at index `i` in `l2_to_l1_message_contexts` within [`private_inputs`](#private-inputs)[`.previous_kernel`](./private-kernel-inner.mdx#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#private-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata): - - If _l2_to_l1_message.value == 0_: - - Verify that _`l2_to_l1_messages[i] == 0`_ + - If `l2_to_l1_message.value == 0`: + - Verify that `l2_to_l1_messages[i] == 0` - Else: - - Verify that _`l2_to_l1_messages[i] == hash(l2_to_l1_message.contract_address, version_id, l2_to_l1_message.portal_contract_address, chain_id, l2_to_l1_message.value)`_ - - Where _version_id_ and _chain_id_ are defined in _[public_inputs](#public-inputs).[constant_data](./private-kernel-initial.md#constantdata).[tx_context](./private-kernel-initial.md#transactioncontext)_. + - Verify that `l2_to_l1_messages[i] == hash(l2_to_l1_message.contract_address, version_id, l2_to_l1_message.portal_contract_address, chain_id, l2_to_l1_message.value)` + - Where `version_id` and `chain_id` are defined in [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata)[`.tx_context`](./private-kernel-initial.mdx#transactioncontext). + +4. Silo `unencrypted_log_hashes`: -4. Silo _unencrypted_log_hashes_: + For each `log_hash` at index `i` in the `unencrypted_log_hash_contexts` within `private_inputs`, if `log_hash.hash != 0`: - For each _log_hash_ at index _i_ in the _unencrypted_log_hash_contexts_ within _private_inputs_, if _`log_hash.hash != 0`_: + `unencrypted_log_hash_contexts[i].value = hash(log_hash.hash, log_hash.contract_address)` - _`unencrypted_log_hash_contexts[i].value = hash(log_hash.hash, log_hash.contract_address)`_ +5. Silo `encrypted_log_hashes`: -5. Silo _encrypted_log_hashes_: + For each `log_hash` at index `i` in the `encrypted_log_hash_contexts` within `private_inputs`, if `log_hash.hash != 0`: - For each _log_hash_ at index _i_ in the _encrypted_log_hash_contexts_ within _private_inputs_, if _`log_hash.hash != 0`_: + `encrypted_log_hash_contexts[i].value = hash(log_hash.hash, contract_address_tag)` - _`encrypted_log_hash_contexts[i].value = hash(log_hash.hash, contract_address_tag)`_ + Where `contract_address_tag = hash(log_hash.contract_address, log_hash.randomness)` - Where _`contract_address_tag = hash(log_hash.contract_address, log_hash.randomness)`_ + #### Verifying ordered arrays. @@ -94,62 +98,62 @@ The initial and inner kernel iterations may produce values in an unordered state This circuit ensures the correct ordering of the following arrays: -- _note_hashes_ -- _nullifiers_ -- _public_call_requests_ -- _ordered_unencrypted_log_hashes_ -- _ordered_encrypted_log_hashes_ -- _ordered_encrypted_note_preimage_hashes_ +- `note_hashes` +- `nullifiers` +- `public_call_requests` +- `ordered_unencrypted_log_hashes` +- `ordered_encrypted_log_hashes` +- `ordered_encrypted_note_preimage_hashes` Where: -- _note_hashes_, _nullifiers_, and _public_call_requests_ are within _[public_inputs](#public-inputs).[accumulated_data](./public-kernel-tail.md#accumulateddata)_. -- _ordered_unencrypted_log_hashes_, _ordered_encrypted_log_hashes_, and _ordered_encrypted_note_preimage_hashes_ are provided as hints through _private_inputs_. -- Every corresponding unordered array for each of the ordered array is sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.md#public-inputs).[transient_accumulated_data](./private-kernel-initial.md#transientaccumulateddata)_. +- `note_hashes`, `nullifiers`, and `public_call_requests` are within [`public_inputs`](#public-inputs)[`.accumulated_data`](./public-kernel-tail.md#accumulateddata). +- `ordered_unencrypted_log_hashes`, `ordered_encrypted_log_hashes`, and `ordered_encrypted_note_preimage_hashes` are provided as hints through `private_inputs`. +- Every corresponding unordered array for each of the ordered array is sourced from [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata). -1. Verify ordered _public_call_requests_: +1. Verify ordered `public_call_requests`: - For each _request_ at index _i_ in _`private_inputs.previous_kernel.public_inputs.transient_accumulated_data.public_call_requests[i]`_, the associated _mapped_request_ is at _`public_call_requests[public_call_request_hints[i]]`_ within _public_inputs_. + For each `request` at index `i` in `private_inputs.previous_kernel.public_inputs.transient_accumulated_data.public_call_requests[i]`, the associated `mapped_request` is at `public_call_requests[public_call_request_hints[i]]` within `public_inputs`. - - If _`request.hash != 0`_, verify that: - - _`request.hash == mapped_request.hash`_ - - _`request.caller_contract == mapped_request.caller_contract`_ - - _`request.caller_context == mapped_request.caller_context`_ - - If _i > 0_, verify that: - - _`mapped_request[i].counter < mapped_request[i - 1].counter`_ + - If `request.hash != 0`, verify that: + - `request.hash == mapped_request.hash` + - `request.caller_contract == mapped_request.caller_contract` + - `request.caller_context == mapped_request.caller_context` + - If `i > 0`, verify that: + - `mapped_request[i].counter < mapped_request[i - 1].counter` - Else: - - All the subsequent requests (_index >= i_) in both _public_call_requests_ and _unordered_requests_ must be empty. + - All the subsequent requests (_index >= i_) in both `public_call_requests` and `unordered_requests` must be empty. - > Note that _public_call_requests_ must be arranged in descending order to ensure the calls are executed in chronological order. + > Note that `public_call_requests` must be arranged in descending order to ensure the calls are executed in chronological order. 2. Verify the rest of the ordered arrays: - For each _note_hash_context_ at index _i_ in the **unordered** _note_hash_contexts_ within _private_inputs_, the associated _note_hash_ is at _`note_hashes[note_hash_hints[i]]`_. + For each `note_hash_context` at index `i` in the **unordered** `note_hash_contexts` within `private_inputs`, the associated `note_hash` is at `note_hashes[note_hash_hints[i]]`. - - If _`note_hash != 0`_, verify that: - - _`note_hash == note_hash_context.value`_ - - If _i > 0_, verify that: - - _`note_hashes[i].counter > note_hashes[i - 1].counter`_ + - If `note_hash != 0`, verify that: + - `note_hash == note_hash_context.value` + - If `i > 0`, verify that: + - `note_hashes[i].counter > note_hashes[i - 1].counter` - Else: - - All the subsequent items (_index >= i_) in both _note_hashes_ and _note_hash_contexts_ must be empty. + - All the subsequent items (index `>= i`) in both `note_hashes` and `note_hash_contexts` must be empty. - Repeat the same process for _nullifiers_, _ordered_unencrypted_log_hashes_, _ordered_encrypted_log_hashes_, and _ordered_encrypted_note_preimage_hashes_. + Repeat the same process for `nullifiers`, `ordered_unencrypted_log_hashes`, `ordered_encrypted_log_hashes`, and `ordered_encrypted_note_preimage_hashes`. > While ordering could occur gradually in each kernel iteration, the implementation is much simpler and **typically** more efficient to be done once in the tail circuit. #### Recalibrating counters. -While the _counter_start_ of a _public_call_request_ is initially assigned in the private function circuit to ensure proper ordering within the transaction, it should be modified in this step. As using _counter_start_ values obtained from private function circuits may leak information. +While the `counter_start` of a `public_call_request` is initially assigned in the private function circuit to ensure proper ordering within the transaction, it should be modified in this step. As using `counter_start` values obtained from private function circuits may leak information. -The _counter_start_ in the _public_call_requests_ within _public_inputs_ should have been recalibrated. This circuit validates the values through the following checks: +The `counter_start` in the `public_call_requests` within `public_inputs` should have been recalibrated. This circuit validates the values through the following checks: -- The _counter_start_ of the non-empty requests are continuous values in descending order: - - _`public_call_requests[i].counter_start == public_call_requests[i + 1].counter_start + 1`_ -- The _counter_start_ of the last non-empty request must be _1_. +- The `counter_start` of the non-empty requests are continuous values in descending order: + - `public_call_requests[i].counter_start == public_call_requests[i + 1].counter_start + 1` +- The `counter_start` of the last non-empty request must be `1`. -> It's crucial for the _counter_start_ of the last request to be _1_, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter _1_. +> It's crucial for the `counter_start` of the last request to be `1`, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter `1`. -> The _counter_end_ for a public call request is determined by the overall count of call requests, reads and writes, note hashes and nullifiers within its scope, including those nested within its child function executions. This calculation will be performed by the sequencer for the executions of public function calls. +> The `counter_end` for a public call request is determined by the overall count of call requests, reads and writes, note hashes and nullifiers within its scope, including those nested within its child function executions. This calculation will be performed by the sequencer for the executions of public function calls. ### Validating Public Inputs @@ -157,65 +161,65 @@ The _counter_start_ in the _public_call_requests_ within _public_inputs_ should 1. The following must align with the results after siloing, as verified in a [previous step](#siloing-values): - - _l2_to_l1_messages_ + - `l2_to_l1_messages` 2. The following must align with the results after ordering, as verified in a [previous step](#verifying-ordered-arrays): - - _note_hashes_ - - _nullifiers_ + - `note_hashes` + - `nullifiers` 3. The hashes and lengths for all logs are accumulated as follows: - For each non-empty _log_hash_ at index _i_ in _ordered_unencrypted_log_hashes_, which is provided as [hints](#hints), and the [ordering](#verifying-ordered-arrays) was verified against the [siloed hashes](#siloing-values) in previous steps: + For each non-empty `log_hash` at index `i` in `ordered_unencrypted_log_hashes`, which is provided as [hints](#hints), and the [ordering](#verifying-ordered-arrays) was verified against the [siloed hashes](#siloing-values) in previous steps: - - _`accumulated_logs_hash = hash(accumulated_logs_hash, log_hash.hash)`_ - - If _i == 0_: _`accumulated_logs_hash = log_hash.hash`_ - - _`accumulated_logs_length += log_hash.length`_ + - `accumulated_logs_hash = hash(accumulated_logs_hash, log_hash.hash)` + - If `i == 0`: `accumulated_logs_hash = log_hash.hash` + - `accumulated_logs_length += log_hash.length` - Check the values in the _public_inputs_ are correct: + Check the values in the `public_inputs` are correct: - - _`unencrypted_logs_hash == accumulated_logs_hash`_ - - _`unencrypted_log_preimages_length == accumulated_logs_length`_ + - `unencrypted_logs_hash == accumulated_logs_hash` + - `unencrypted_log_preimages_length == accumulated_logs_length` - Repeat the same process for _encrypted_logs_hash_, _encrypted_log_preimages_length_, _encrypted_note_preimages_hash_ and _encrypted_note_preimages_length_. + Repeat the same process for `encrypted_logs_hash`, `encrypted_log_preimages_length`, `encrypted_note_preimages_hash` and `encrypted_note_preimages_length`. 4. The following must be empty: - - _old_public_data_tree_snapshot_ - - _new_public_data_tree_snapshot_ + - `old_public_data_tree_snapshot` + - `new_public_data_tree_snapshot` #### Verifying the transient accumulated data. -It ensures that all data in the _[transient_accumulated_data](./public-kernel-tail.md#transientaccumulateddata)_ within _[public_inputs](#public-inputs)_ is empty, with the exception of the _public_call_requests_. +It ensures that all data in the [`transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata) within [`public_inputs`](#public-inputs) is empty, with the exception of the `public_call_requests`. -The _public_call_requests_ must [adhere to a specific order](#verifying-ordered-arrays) with [recalibrated counters](#recalibrating-counters), as verified in the previous steps. +The `public_call_requests` must [adhere to a specific order](#verifying-ordered-arrays) with [recalibrated counters](#recalibrating-counters), as verified in the previous steps. #### Verifying the constant data. -This section follows the same [process](./private-kernel-inner.md#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. -## Private Inputs +## `PrivateInputs` -### _PreviousKernel_ +### `PreviousKernel` -The format aligns with the _[PreviousKernel](./private-kernel-inner.md#previouskernel)_ of the inner private kernel circuit. +The format aligns with the [PreviousKernel](./private-kernel-inner.mdx#previouskernel) of the inner private kernel circuit. ### _Hints_ Data that aids in the verifications carried out in this circuit: -| Field | Type | Description | -| ---------------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| _note_hash_hints_ | [_field_; _C_] | Indices of ordered _note_hashes_ for _note_hash_contexts_. _C_ equals the length of _note_hash_contexts_. | -| _nullifier_hints_ | [_field_; _C_] | Indices of ordered _nullifiers_ for _nullifier_contexts_. _C_ equals the length of _nullifier_contexts_. | -| _public_call_request_hints_ | [_field_; _C_] | Indices of ordered _public_call_requests_ for _public_call_requests_. _C_ equals the length of _public_call_requests_. | -| _ordered_unencrypted_log_hashes_ | [_field_; _C_] | Ordered _unencrypted_log_hashes_. _C_ equals the length of _unencrypted_log_hash_contexts_. | -| _unencrypted_log_hash_hints_ | [_field_; _C_] | Indices of _ordered_unencrypted_log_hashes_ for _unencrypted_log_hash_contexts_. _C_ equals the length of _unencrypted_log_hash_contexts_. | -| _ordered_encrypted_log_hashes_ | [_field_; _C_] | Ordered _encrypted_log_hashes_. _C_ equals the length of _encrypted_log_hash_contexts_. | -| _encrypted_log_hash_hints_ | [_field_; _C_] | Indices of _ordered_encrypted_log_hashes_ for _encrypted_log_hash_contexts_. _C_ equals the length of _encrypted_log_hash_contexts_. | -| _ordered_encrypted_note_preimage_hashes_ | [_field_; _C_] | Ordered _encrypted_note_preimage_hashes_. _C_ equals the length of _encrypted_note_preimage_hash_contexts_. | -| _encrypted_note_preimage_hints_ | [_field_; _C_] | Indices of _ordered_encrypted_note_preimage_hashes_ for _encrypted_note_preimage_hash_contexts_. _C_ equals the length of _encrypted_note_preimage_hash_contexts_. | - -## Public Inputs - -The format aligns with the _[Public Inputs](./public-kernel-tail.md#public-inputs)_ of the tail public kernel circuit. +| Field | Type | Description | +| ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `note_hash_hints` | `[field; C]` | Indices of ordered `note_hashes` for `note_hash_contexts`. `C` equals the length of `note_hash_contexts`. | +| `nullifier_hints` | `[field; C]` | Indices of ordered `nullifiers` for `nullifier_contexts`. `C` equals the length of `nullifier_contexts`. | +| `public_call_request_hints` | `[field; C]` | Indices of ordered `public_call_requests` for `public_call_requests`. `C` equals the length of `public_call_requests`. | +| `ordered_unencrypted_log_hashes` | `[field; C]` | Ordered `unencrypted_log_hashes`. `C` equals the length of `unencrypted_log_hash_contexts`. | +| `unencrypted_log_hash_hints` | `[field; C]` | Indices of `ordered_unencrypted_log_hashes` for `unencrypted_log_hash_contexts`. `C` equals the length of `unencrypted_log_hash_contexts`. | +| `ordered_encrypted_log_hashes` | `[field; C]` | Ordered `encrypted_log_hashes`. `C` equals the length of `encrypted_log_hash_contexts`. | +| `encrypted_log_hash_hints` | `[field; C]` | Indices of `ordered_encrypted_log_hashes` for `encrypted_log_hash_contexts`. `C` equals the length of `encrypted_log_hash_contexts`. | +| `ordered_encrypted_note_preimage_hashes` | `[field; C]` | Ordered `encrypted_note_preimage_hashes`. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | +| `encrypted_note_preimage_hints` | `[field; C]` | Indices of `ordered_encrypted_note_preimage_hashes` for `encrypted_note_preimage_hash_contexts`. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | + +## `PublicInputs` + +The format aligns with the [Public Inputs](./public-kernel-tail.md#public-inputs) of the tail public kernel circuit. diff --git a/yellow-paper/docs/circuits/public-kernel-initial.md b/yellow-paper/docs/circuits/public-kernel-initial.md index be814bed9af..d813922e9b1 100644 --- a/yellow-paper/docs/circuits/public-kernel-initial.md +++ b/yellow-paper/docs/circuits/public-kernel-initial.md @@ -1,5 +1,9 @@ # Public Kernel Circuit - Initial +:::Danger +The public kernel circuits are being redesigned to accommodate the latest AVM designs. This page is therefore highly likely to change significantly. +::: + ## Requirements The **initial** public kernel iteration undergoes processes to prepare the necessary data for the executions of the public function calls. @@ -8,7 +12,7 @@ The **initial** public kernel iteration undergoes processes to prepare the neces #### Verifying the previous kernel proof. -It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. +It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel). The preceding proof can only be: @@ -20,38 +24,38 @@ The preceding proof can only be: While the counters outputted from the tail private kernel circuit preserve the correct ordering of the _public_call_requests_, they do not reflect the actual number of side effects each public call entails. This circuit allows the recalibration of counters for _public_call_requests_, ensuring subsequent public kernels can be executed with the correct counter range. -For each _request_ at index _i_ in the _public_call_requests_ within _[public_inputs](#public-inputs).[transient_accumulated_data](./public-kernel-tail.md#transientaccumulateddata)_: +For each _request_ at index _i_ in the _public_call_requests_ within [`public_inputs`](#public-inputs).[`.transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata): 1. Its hash must match the corresponding item in the _public_call_requests_ within the previous kernel's public inputs: - - _`request.hash == private_inputs.previous_kernel_public_inputs.public_call_requests[i].hash`_ -2. Its _counter_end_ must be greater than its _counter_start_. -3. Its _counter_start_ must be greater than the _counter_end_ of the item at index _i + 1_. -4. If it's the last item, its _counter_start_ must be _1_. + - `request.hash == private_inputs.previous_kernel_public_inputs.public_call_requests[i].hash` +2. Its `counter_end` must be greater than its `counter_start`. +3. Its `counter_start` must be greater than the `counter_end` of the item at index `i + 1`. +4. If it's the last item, its `counter_start` must be `1`. -> It's crucial for the _counter_start_ of the last item to be _1_, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter _1_. +> It's crucial for the `counter_start` of the last item to be `1`, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter `1`. ### Validating Public Inputs #### Verifying the accumulated data. -It ensures that the _accumulated_data_ in the _[public_inputs](#public-inputs)_ matches the _accumulated_data_ in _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./public-kernel-tail.md#public-inputs)_. +It ensures that the `accumulated_data` in the [`public_inputs`](#public-inputs) matches the `accumulated_data` in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./public-kernel-tail.md#public-inputs). #### Verifying the transient accumulated data. -It ensures that all data in the _[transient_accumulated_data](./public-kernel-tail.md#transientaccumulateddata)_ within _[public_inputs](#public-inputs)_ is empty, with the exception of the _public_call_requests_. +It ensures that all data in the [`transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata) within [`public_inputs`](#public-inputs) is empty, with the exception of the `public_call_requests`. -The values in _public_call_requests_ are verified in a [previous step](#recalibrating-counters). +The values in `public_call_requests` are verified in a [previous step](#recalibrating-counters). #### Verifying the constant data. -This section follows the same [process](./private-kernel-inner.md#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. -## Private Inputs +## `PrivateInputs` -### _PreviousKernel_ +### `PreviousKernel` -The format aligns with the _[PreviousKernel](./private-kernel-tail.md#previouskernel)_ of the tail public kernel circuit. +The format aligns with the [PreviousKernel](./private-kernel-tail.md#previouskernel)` of the tail public kernel circuit. -## Public Inputs +## `PublicInputs` -The format aligns with the _[Public Inputs](./public-kernel-tail.md#public-inputs)_ of the tail public kernel circuit. +The format aligns with the [`PublicInputs`](./public-kernel-tail.md#public-inputs)` of the tail public kernel circuit. diff --git a/yellow-paper/docs/circuits/public-kernel-inner.md b/yellow-paper/docs/circuits/public-kernel-inner.md index 1bf0af700c8..887260c52ce 100644 --- a/yellow-paper/docs/circuits/public-kernel-inner.md +++ b/yellow-paper/docs/circuits/public-kernel-inner.md @@ -1,5 +1,9 @@ # Public Kernel Circuit - Inner +:::Danger +The public kernel circuits are being redesigned to accommodate the latest AVM designs. This page is therefore highly likely to change significantly. +::: + ## Requirements In the public kernel iteration, the process involves taking a previous iteration and public call data, verifying their integrity, and preparing the necessary data for subsequent circuits to operate. @@ -8,7 +12,7 @@ In the public kernel iteration, the process involves taking a previous iteration #### Verifying the previous kernel proof. -It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. +It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from [private_inputs](#private-inputs).[previous_kernel](#previouskernel). The preceding proof can be: @@ -19,45 +23,45 @@ The preceding proof can be: #### Ensuring the function being called exists in the contract. -This section follows the same [process](./private-kernel-initial.md#ensuring-the-function-being-called-exists-in-the-contract) as outlined in the initial private kernel circuit. +This section follows the same [process](./private-kernel-initial.mdx#ensuring-the-function-being-called-exists-in-the-contract) as outlined in the initial private kernel circuit. #### Ensuring the contract instance being called is deployed. It verifies the public deployment of the contract instance by conducting a membership proof, where: -- The leaf is a nullifier emitting from the deployer contract, computed as _`hash(deployer_address, contract_address)`_, where: - - _deployer_address_ is defined in _[private_inputs](#private-inputs).[public_call](#publiccall).[contract_data](../contract-deployment/instances.md#structure)_. - - _contract_data_ is defined in _[private_inputs](#private-inputs).[public_call](#publiccall).[call_stack_item](#publiccallstackitem)_. -- The index and sibling path are provided in _contract_deployment_membership_witness_ through _[private_inputs](#private-inputs).[public_call](#publiccall)_. -- The root is the _nullifier_tree_root_ in the _[header](./private-function.md#header)_ within _[public_inputs](#public-inputs).[constant_data](./private-kernel-initial.md#constantdata)_. +- The leaf is a nullifier emitting from the deployer contract, computed as `hash(deployer_address, contract_address)`, where: + - `deployer_address` is defined in [`private_inputs`](#private-inputs)[`.public_call`](#publiccall)[`.contract_data`](../contract-deployment/instances.md#structure). + - `contract_data` is defined in [`private_inputs`](#private-inputs)[`.public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem). +- The index and sibling path are provided in `contract_deployment_membership_witness` through [`private_inputs`](#private-inputs)[`.public_call`](#publiccall)\_. +- The root is the `nullifier_tree_root` in the [`header`](./private-function.md#header) within [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata). #### Ensuring the function is legitimate: -For the _[function_data](./private-kernel-initial.md#functiondata)_ in _[public_call](#publiccall).[call_stack_item](#publiccallstackitem)_, this circuit verifies that: +For the [`function_data`](./private-kernel-initial.mdx#functiondata) in [`public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem), this circuit verifies that: - It must be a public function: - - _`function_data.function_type == public`_ + - `function_data.function_type == public` #### Ensuring the current call matches the call request. -The top item in the _public_call_requests_ of the _[previous_kernel](#previouskernel)_ must pertain to the current function call. +The top item in the `public_call_requests` of the [`previous_kernel`](#previouskernel) must pertain to the current function call. This circuit will: 1. Pop the request from the stack: - - _`call_request = previous_kernel.public_inputs.transient_accumulated_data.public_call_requests.pop()`_ + - `call_request = previous_kernel.public_inputs.transient_accumulated_data.public_call_requests.pop()` 2. Compare the hash with that of the current function call: - - _`call_request.hash == public_call.call_stack_item.hash()`_ - - The hash of the _call_stack_item_ is computed as: - - _`hash(contract_address, function_data.hash(), public_inputs.hash(), counter_start, counter_end)`_ - - Where _function_data.hash()_ and _public_inputs.hash()_ are the hashes of the serialized field elements. + - `call_request.hash == public_call.call_stack_item.hash()` + - The hash of the `call_stack_item` is computed as: + - `hash(contract_address, function_data.hash(), public_inputs.hash(), counter_start, counter_end)` + - Where `function_data.hash()` and `public_inputs.hash()` are the hashes of the serialized field elements. #### Ensuring this function is called with the correct context. -This section follows the same [process](./private-kernel-inner.md#ensuring-this-function-is-called-with-the-correct-context) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#ensuring-this-function-is-called-with-the-correct-context) as outlined in the inner private kernel circuit. #### Verifying the public function proof. @@ -65,112 +69,112 @@ It verifies that the public function was executed with the provided proof data, #### Verifying the public inputs of the public function circuit. -It ensures the public function's intention by checking the following in _[public_call](#publiccall).[call_stack_item](#publiccallstackitem).[public_inputs](#publicfunctionpublicinputs)_: +It ensures the public function's intention by checking the following in [`public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem)[`.public_inputs`](#publicfunctionpublicinputs): -- The _header_ must match the one in the _[constant_data](./private-kernel-initial.md#constantdata)_. -- If it is a static call (_`public_inputs.call_context.is_static_call == true`_), it ensures that the function does not induce any state changes by verifying that the following arrays are empty: - - _note_hashes_ - - _nullifiers_ - - _l2_to_l1_messages_ - - _storage_writes_ - - _unencrypted_log_hashes_ +- The `header` must match the one in the [`constant_data`](./private-kernel-initial.mdx#constantdata). +- If it is a static call (`public_inputs.call_context.is_static_call == true`), it ensures that the function does not induce any state changes by verifying that the following arrays are empty: + - `note_hashes` + - `nullifiers` + - `l2_to_l1_messages` + - `storage_writes` + - `unencrypted_log_hashes` #### Verifying the counters. It verifies that each value listed below is associated with a legitimate counter. -1. For the _[call_stack_item](#privatecallstackitem)_: +1. For the [`call_stack_item`](#privatecallstackitem): - - The _counter_start_ and _counter_end_ must match those in the _call_request_ [popped](#ensuring-the-current-call-matches-the-call-request) from the _public_call_requests_ in a previous step. + - The `counter_start` and `counter_end` must match those in the `call_request` [popped](#ensuring-the-current-call-matches-the-call-request) from the `public_call_requests` in a previous step. -2. For items in each ordered array in _[call_stack_item](#publiccallstackitem).[public_inputs](#publicfunctionpublicinputs)_: +2. For items in each ordered array in [`call_stack_item`](#publiccallstackitem)[`.public_inputs`](#publicfunctionpublicinputs): - - The counter of the first item must be greater than the _counter_start_ of the current call. + - The counter of the first item must be greater than the `counter_start` of the current call. - The counter of each subsequent item must be greater than the counter of the previous item. - - The counter of the last item must be less than the _counter_end_ of the current call. + - The counter of the last item must be less than the `counter_end` of the current call. The ordered arrays include: - - _storage_reads_ - - _storage_writes_ + - `storage_reads` + - `storage_writes` -3. For the last _N_ non-empty requests in _public_call_requests_ within _[public_inputs](#public-inputs).[transient_accumulated_data](#transientaccumulateddata)_: +3. For the last `N` non-empty requests in `public_call_requests` within [`public_inputs`](#public-inputs)[`.transient_accumulated_data`](#transientaccumulateddata): - - The _counter_end_ of each request must be greater than its _counter_start_. - - The _counter_start_ of the first request must be greater than the _counter_start_ of the _call_stack_item_. - - The _counter_start_ of the second and subsequent requests must be greater than the _counter_end_ of the previous request. - - The _counter_end_ of the last request must be less than the _counter_end_ of the _call_stack_item_. + - The `counter_end` of each request must be greater than its `counter_start`. + - The `counter_start` of the first request must be greater than the `counter_start` of the `call_stack_item`. + - The `counter_start` of the second and subsequent requests must be greater than the `counter_end` of the previous request. + - The `counter_end` of the last request must be less than the `counter_end` of the `call_stack_item`. - > _N_ is the number of non-zero hashes in the _public_call_stack_item_hashes_ in _[private_inputs](#private-inputs).[public_call](#publiccall).[public_inputs](#publicfunctionpublicinputs)_. + > `N` is the number of non-zero hashes in the `public_call_stack_item_hashes` in [`private_inputs`](#private-inputs)[`.public_call`](#publiccall)[`.public_inputs`](#publicfunctionpublicinputs). ### Validating Public Inputs #### Verifying the accumulated data. -1. It verifies that the following in the _[accumulated_data](#accumulateddata)_ align with their corresponding values in _[public_call](#publiccall).[call_stack_item](#publiccallstackitem).[public_inputs](#publicfunctionpublicinputs)_. +1. It verifies that the following in the [`accumulated_data`](#accumulateddata) align with their corresponding values in [`public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem)[`.public_inputs`](#publicfunctionpublicinputs). - - _note_hashes_ - - _nullifiers_ - - _l2_to_l1_messages_ - - _encrypted_logs_hash_ - - _encrypted_log_preimages_length_ - - _encrypted_note_preimages_hash_ - - _encrypted_note_preimages_length_ - - _old_public_data_tree_snapshot_ - - _new_public_data_tree_snapshot_ + - `note_hashes` + - `nullifiers` + - `l2_to_l1_messages` + - `encrypted_logs_hash` + - `encrypted_log_preimages_length` + - `encrypted_note_preimages_hash` + - `encrypted_note_preimages_length` + - `old_public_data_tree_snapshot` + - `new_public_data_tree_snapshot` #### Verifying the transient accumulated data. -The _[transient_accumulated_data](./public-kernel-tail.md#transientaccumulateddata)_ in this circuit's _[public_inputs](#public-inputs)_ includes values from both the previous iterations and the _[public_call](#publiccall)_. +The [`transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata) in this circuit's [`public_inputs`](#public-inputs)\_ includes values from both the previous iterations and the [`public_call`](#publiccall). -For each array in the _transient_accumulated_data_, this circuit verifies that it is populated with the values from the previous iterations, specifically: +For each array in the `transient_accumulated_data`, this circuit verifies that it is populated with the values from the previous iterations, specifically: -- _`public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]`_ +- `public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]` -> It's important to note that the top item in the _public_call_requests_ from the _previous_kernel_ won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). +> It's important to note that the top item in the `public_call_requests` from the _previous_kernel_ won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). -For the subsequent items appended after the values from the previous iterations, they constitute the values from _[private_inputs](#private-inputs).[public_call](#publiccall).[call_stack_item](#publiccallstackitem).[public_inputs](#publicfunctionpublicinputs)_ (_public_function_public_inputs_), and must undergo the following verifications: +For the subsequent items appended after the values from the previous iterations, they constitute the values from [`private_inputs`](#private-inputs).[public_call](#publiccall).[call_stack_item](#publiccallstackitem).[public_inputs](#publicfunctionpublicinputs) (`public_function_public_inputs`), and must undergo the following verifications: -1. Ensure that the specified values in the following arrays match those in the corresponding arrays in the _public_function_public_inputs_: +1. Ensure that the specified values in the following arrays match those in the corresponding arrays in the `public_function_public_inputs`: - - _note_hash_contexts_ - - _value_, _counter_ - - _nullifier_contexts_ - - _value_, _counter_ - - _l2_to_l1_message_contexts_ - - _value_ - - _storage_reads_ - - _value_, _counter_ - - _storage_writes_ - - _value_, _counter_ - - _unencrypted_log_hash_contexts_ - - _hash_, _length_, _counter_ + - `note_hash_contexts` + - `value`, `counter` + - `nullifier_contexts` + - `value`, `counter` + - `l2_to_l1_message_contexts` + - `value` + - `storage_reads` + - `value`, `counter` + - `storage_writes` + - `value`, `counter` + - `unencrypted_log_hash_contexts` + - `hash`, `length`, `counter` -2. For _public_call_requests_: +2. For `public_call_requests`: - - The hashes align with the values in the _public_call_stack_item_hashes_ within _public_function_public_inputs_, but in **reverse** order. - - The _caller_contract_address_ equals the _contract_address_ in _[public_call](#publiccall).[call_stack_item](#publiccallstackitem)_. - - The _caller_context_ aligns with the values in the _call_context_ within _public_function_public_inputs_. + - The hashes align with the values in the `public_call_stack_item_hashes` within `public_function_public_inputs`, but in **reverse** order. + - The `caller_contract_address` equals the `contract_address` in [`public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem). + - The `caller_context` aligns with the values in the `call_context` within `public_function_public_inputs`. > It's important that the call requests are arranged in reverse order to ensure they are executed in chronological order. -3. The _contract_address_ for each non-empty item in the following arrays must equal the _storage_contract_address_ defined in _public_function_public_inputs.call_context_: +3. The `contract_address` for each non-empty item in the following arrays must equal the `storage_contract_address` defined in `public_function_public_inputs.call_context`: - - _note_hash_contexts_ - - _nullifier_contexts_ - - _l2_to_l1_message_contexts_ - - _storage_reads_ - - _storage_writes_ - - _unencrypted_log_hash_contexts_ + - `note_hash_contexts` + - `nullifier_contexts` + - `l2_to_l1_message_contexts` + - `storage_reads` + - `storage_writes` + - `unencrypted_log_hash_contexts` > Ensuring the alignment of the contract addresses is crucial, as it is later used to [silo the values](./public-kernel-tail.md#siloing-values) and to establish associations with values within the same contract. -4. The _portal_contract_address_ for each non-empty item in _l2_to_l1_message_contexts_ must equal the _portal_contract_address_ defined in _public_function_public_inputs.call_context_. +4. The _portal_contract_address_ for each non-empty item in `l2_to_l1_message_contexts` must equal the _portal_contract_address_ defined in _public_function_public_inputs.call_context_. -5. For each _storage_write_ in _storage_writes_, verify that it is associated with an _override_counter_. The value of the _override_counter_ can be: +5. For each `storage_write` in `storage_writes`, verify that it is associated with an _override_counter_. The value of the _override_counter_ can be: - - Zero: if the _storage_slot_ does not change later in the same transaction. - - Greater than _storage_write.counter_: if the _storage_slot_ is written again later in the same transaction. + - Zero: if the `storage_slot` does not change later in the same transaction. + - Greater than `storage_write.counter`: if the `storage_slot` is written again later in the same transaction. > Override counters are used in the [tail public kernel circuit](./public-kernel-tail.md) to ensure a read happens **before** the value is changed in a subsequent write. @@ -178,61 +182,61 @@ For the subsequent items appended after the values from the previous iterations, #### Verifying the constant data. -This section follows the same [process](./private-kernel-inner.md#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. -## Private Inputs +## `PrivateInputs` -### _PreviousKernel_ +### `PreviousKernel` -The format aligns with the _[PreviousKernel](./private-kernel-tail.md#previouskernel)_ of the tail public kernel circuit. +The format aligns with the [`PreviousKernel`](./private-kernel-tail.md#previouskernel) of the tail public kernel circuit. -### _PublicCall_ +### `PublicCall` Data that holds details about the current public function call. -| Field | Type | Description | -| ---------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------- | -| _call_stack_item_ | _[PublicCallStackItem](#publiccallstackitem)_ | Information about the current public function call. | -| _proof_ | _Proof_ | Proof of the public function circuit. | -| _vk_ | _VerificationKey_ | Verification key of the public function circuit. | -| _bytecode_hash_ | _field_ | Hash of the function bytecode. | -| _contract_data_ | _[ContractInstance](../contract-deployment/instances.md#structure)_ | Data of the contract instance being called. | -| _contract_class_data_ | _[ContractClassData](./private-kernel-initial.md#contractclassdata)_ | Data of the contract class. | -| _function_leaf_membership_witness_ | _[MembershipWitness](./private-kernel-inner.md#membershipwitness)_ | Membership witness for the function being called. | -| _contract_deployment_membership_witness_ | _[MembershipWitness](./private-kernel-inner.md#membershipwitness)_ | Membership witness for the deployment of the contract being called. | +| Field | Type | Description | +| ---------------------------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------- | +| `call_stack_item` | [`PublicCallStackItem`](#publiccallstackitem) | Information about the current public function call. | +| `proof` | `Proof` | Proof of the public function circuit. | +| `vk` | `VerificationKey` | Verification key of the public function circuit. | +| `bytecode_hash` | `field` | Hash of the function bytecode. | +| `contract_data` | [`ContractInstance`](../contract-deployment/instances.md#structure) | Data of the contract instance being called. | +| `contract_class_data` | [`ContractClass`](./private-kernel-initial.mdx#contractclassdata) | Data of the contract class. | +| `function_leaf_membership_witness` | [`MembershipWitness`](./private-kernel-inner.mdx#membershipwitness) | Membership witness for the function being called. | +| `contract_deployment_membership_witness` | [`MembershipWitness`](./private-kernel-inner.mdx#membershipwitness) | Membership witness for the deployment of the contract being called. | -## Public Inputs +## `PublicInputs` -The format aligns with the _[Public Inputs](./public-kernel-tail.md#public-inputs)_ of the tail public kernel circuit. +The format aligns with the [`PublicInputs`](./public-kernel-tail.md#public-inputs) of the tail public kernel circuit. ## Types -### _PublicCallStackItem_ +### `PublicCallStackItem` | Field | Type | Description | | ------------------ | ----------------------------------------------------------- | --------------------------------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract on which the function is invoked. | -| _function_data_ | _[FunctionData](#functiondata)_ | Data of the function being called. | -| _public_inputs_ | _[PublicFunctionPublicInputs](#publicfunctionpublicinputs)_ | Public inputs of the public vm circuit. | -| _counter_start_ | _field_ | Counter at which the function call was initiated. | -| _counter_end_ | _field_ | Counter at which the function call ended. | - -### _PublicFunctionPublicInputs_ - -| Field | Type | Description | -| ------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------- | -| _call_context_ | _[CallContext](./private-function.md#callcontext)_ | Context of the call corresponding to this function execution. | -| _args_hash_ | _field_ | Hash of the function arguments. | -| _return_values_ | [_field_; _C_] | Return values of this function call. | -| _note_hashes_ | [_[NoteHash](./private-function.md#notehash)_; _C_] | New note hashes created in this function call. | -| _nullifiers_ | [_[Nullifier](./private-function.md#nullifier)_; _C_] | New nullifiers created in this function call. | -| _l2_to_l1_messages_ | [_field_; _C_] | New L2 to L1 messages created in this function call. | -| _storage_reads_ | [_[StorageRead](./public-kernel-tail.md#storageread)_; _C_] | Data read from the public data tree. | -| _storage_writes_ | [_[StorageWrite](./public-kernel-tail.md#storagewrite)_; _C_] | Data written to the public data tree. | -| _unencrypted_log_hashes_ | [_[UnencryptedLogHash](./private-function.md#unencryptedloghash)_; _C_] | Hashes of the unencrypted logs emitted in this function call. | -| _public_call_stack_item_hashes_ | [_field_; _C_] | Hashes of the public function calls initiated by this function. | -| _header_ | _[Header](./private-function.md#header)_ | Information about the trees used for the transaction. | -| _chain_id_ | _field_ | Chain ID of the transaction. | -| _version_ | _field_ | Version of the transaction. | +| `contract_address` | `AztecAddress` | Address of the contract on which the function is invoked. | +| `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | +| `public_inputs` | [`PublicFunctionPublicInputs`](#publicfunctionpublicinputs) | Public inputs of the public vm circuit. | +| `counter_start` | `field` | Counter at which the function call was initiated. | +| `counter_end` | `field` | Counter at which the function call ended. | + +### `PublicFunctionPublicInputs` + +| Field | Type | Description | +| ------------------------------- | --------------------------------------------------------------------- | --------------------------------------------------------------- | +| `call_context` | [`CallContext`](./private-function.md#callcontext) | Context of the call corresponding to this function execution. | +| `args_hash` | `field` | Hash of the function arguments. | +| `return_values` | `[field; C]` | Return values of this function call. | +| `note_hashes` | `[`[`NoteHash`](./private-function.md#notehash)`; C]` | New note hashes created in this function call. | +| `nullifiers` | [`[Nullifier; C]`](./private-function.md#nullifier) | New nullifiers created in this function call. | +| `l2_to_l1_messages` | `[field; C]` | New L2 to L1 messages created in this function call. | +| `storage_reads` | [`[StorageRead_; C]`](./public-kernel-tail.md#storageread) | Data read from the public data tree. | +| `storage_writes` | [`[StorageWrite; C]`](./public-kernel-tail.md#storagewrite) | Data written to the public data tree. | +| `unencrypted_log_hashes` | [`[UnencryptedLogHash; C]`](./private-function.md#unencryptedloghash) | Hashes of the unencrypted logs emitted in this function call. | +| `public_call_stack_item_hashes` | `[field; C]` | Hashes of the public function calls initiated by this function. | +| `header` | [`Header`](./private-function.md#header) | Information about the trees used for the transaction. | +| `chain_id` | `field` | Chain ID of the transaction. | +| `version` | `field` | Version of the transaction. | > The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. diff --git a/yellow-paper/docs/circuits/public-kernel-tail.md b/yellow-paper/docs/circuits/public-kernel-tail.md index 69631ea47c5..4c0f0bae098 100644 --- a/yellow-paper/docs/circuits/public-kernel-tail.md +++ b/yellow-paper/docs/circuits/public-kernel-tail.md @@ -1,5 +1,9 @@ # Public Kernel Circuit - Tail +:::Danger +The public kernel circuits are being redesigned to accommodate the latest AVM designs. This page is therefore highly likely to change significantly. +::: + ## Requirements The **tail** circuit refrains from processing individual public function calls. Instead, it integrates the results of inner public kernel circuit and performs additional verification and processing necessary for generating the final public inputs. @@ -8,7 +12,7 @@ The **tail** circuit refrains from processing individual public function calls. #### Verifying the previous kernel proof. -It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from _[private_inputs](#private-inputs).[previous_kernel](#previouskernel)_. +It verifies that the previous iteration was executed successfully with the given proof data, verification key, and public inputs, sourced from [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel). The preceding proof can only be: @@ -18,7 +22,7 @@ The preceding proof can only be: The following must be empty to ensure all the public function calls are processed: -- _public_call_requests_ within _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./public-kernel-tail.md#public-inputs).[transient_accumulated_data](./public-kernel-tail.md#transientaccumulateddata)_. +- `public_call_requests` within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./public-kernel-tail.md#public-inputs)[`.transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata). ### Processing Final Outputs @@ -26,10 +30,10 @@ The following must be empty to ensure all the public function calls are processe This section follows the same [process](./private-kernel-tail.md#siloing-values) as outlined in the tail private kernel circuit. -Additionally, it silos the _storage_slot_ of each non-empty item in the following arrays: +Additionally, it silos the `storage_slot` of each non-empty item in the following arrays: -- _storage_reads_ -- _storage_writes_ +- `storage_reads` +- `storage_writes` The siloed storage slot is computed as: `hash(contract_address, storage_slot)`. @@ -39,173 +43,173 @@ The iterations of the public kernel may yield values in an unordered state due t This circuit ensures the correct ordering of the following: -- _note_hashes_ -- _nullifiers_ -- _storage_reads_ -- _storage_writes_ -- _ordered_unencrypted_log_hashes_ +- `note_hashes` +- `nullifiers` +- `storage_reads` +- `storage_writes` +- `ordered_unencrypted_log_hashes` -1. For _note_hashes_, _nullifiers_, and _ordered_unencrypted_log_hashes_, they undergo the same [process](./private-kernel-tail.md#verifying-ordered-arrays) as outlined in the tail private kernel circuit. With the exception that the loop starts from index _offset + i_, where _offset_ is the number of non-zero values in the _note_hashes_ and _nullifiers_ arrays within _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./public-kernel-tail.md#public-inputs).[accumulated_data](./public-kernel-tail.md#accumulateddata)_. +1. For `note_hashes`, `nullifiers`, and `ordered_unencrypted_log_hashes`, they undergo the same [process](./private-kernel-tail.md#verifying-ordered-arrays) as outlined in the tail private kernel circuit. With the exception that the loop starts from index `offset + i`, where `offset` is the number of non-zero values in the `note_hashes` and `nullifiers` arrays within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./public-kernel-tail.md#public-inputs)[`.accumulated_data`](./public-kernel-tail.md#accumulateddata). -2. For _storage_reads_, an _ordered_storage_reads_ and _storage_read_hints_ are provided as [hints](#hints) through _private_inputs_. This circuit checks that: +2. For `storage_reads`, an `ordered_storage_reads` and `storage_read_hints` are provided as [hints](#hints) through `private_inputs`. This circuit checks that: - For each _read_ at index _i_ in _`storage_reads[i]`_, the associated _mapped_read_ is at _`ordered_storage_reads[storage_read_hints[i]]`_. + For each `read` at index `i` in `storage_reads[i]`, the associated `mapped_read` is at `ordered_storage_reads[storage_read_hints[i]]`. - - If _`read.is_empty() == false`_, verify that: - - All values in _read_ align with those in _mapped_read_: - - _`read.contract_address == mapped_read.contract_address`_ - - _`read.storage_slot == mapped_read.storage_slot`_ - - _`read.value == mapped_read.value`_ - - _`read.counter == mapped_read.counter`_ - - If _i > 0_, verify that: - - _`mapped_read[i].counter > mapped_read[i - 1].counter`_ + - If `read.is_empty() == false`, verify that: + - All values in `read` align with those in `mapped_read`: + - `read.contract_address == mapped_read.contract_address` + - `read.storage_slot == mapped_read.storage_slot` + - `read.value == mapped_read.value` + - `read.counter == mapped_read.counter` + - If `i > 0`, verify that: + - `mapped_read[i].counter > mapped_read[i - 1].counter` - Else: - - All the subsequent reads (_index >= i_) in both _storage_reads_ and _ordered_storage_reads_ must be empty. + - All the subsequent reads (index `>= i`) in both `storage_reads` and `ordered_storage_reads` must be empty. -3. For _storage_writes_, an _ordered_storage_writes_ and _storage_write_hints_ are provided as [hints](#hints) through _private_inputs_. The verification is the same as the process for _storage_reads_. +3. For `storage_writes`, an `ordered_storage_writes` and `storage_write_hints` are provided as [hints](#hints) through `private_inputs`. The verification is the same as the process for `storage_reads`. #### Verifying public data snaps. -The _public_data_snaps_ is provided through _private_inputs_, serving as hints for _storage_reads_ to prove that the value in the tree aligns with the read operation. For _storage_writes_, it substantiates the presence or absence of the storage slot in the public data tree. +The `public_data_snaps` is provided through `private_inputs`, serving as hints for `storage_reads` to prove that the value in the tree aligns with the read operation. For `storage_writes`, it substantiates the presence or absence of the storage slot in the public data tree. -A _[public_data_snap](#publicdatasnap)_ contains: +A [public_data_snap](#publicdatasnap) contains: -- A _storage_slot_ and its _value_. -- An _override_counter_, indicating the counter of the first _storage_write_ that writes to the storage slot. Zero if the storage slot is not written in this transaction. -- A flag _exists_ indicating its presence or absence in the public data tree. +- A `storage_slot` and its `value`. +- An `override_counter`, indicating the counter of the first `storage_write` that writes to the storage slot. Zero if the storage slot is not written in this transaction. +- A flag `exists` indicating its presence or absence in the public data tree. -This circuit ensures the uniqueness of each snap in _public_data_snaps_. It verifies that: +This circuit ensures the uniqueness of each snap in `public_data_snaps`. It verifies that: -For each snap at index _i_, where _i_ > 0: +For each snap at index `i`, where `i` > 0: -- If _snap.is_empty() == false_ - - _`snap.storage_slot > public_data_snaps[i - 1].storage_slot`_ +- If `snap.is_empty() == false` + - `snap.storage_slot > public_data_snaps[i - 1].storage_slot` > It is crucial for each snap to be unique, as duplicated snaps would disrupt a group of writes for the same storage slot. This could enable the unauthorized act of reading the old value after it has been updated. #### Grouping storage writes. -To facilitate the verification of _storage_reads_ and streamline _storage_writes_, it is imperative to establish connections between writes targeting the same storage slot. Furthermore, the first write in a group must be linked to a _public_data_snap_, ensuring the dataset has progressed from the right initial state. +To facilitate the verification of `storage_reads` and streamline `storage_writes`, it is imperative to establish connections between writes targeting the same storage slot. Furthermore, the first write in a group must be linked to a `public_data_snap`, ensuring the dataset has progressed from the right initial state. -A new field, _prev_counter_, is incorporated to the _ordered_storage_writes_ to indicate whether each write has a preceding snap or write. Another field, _exists_, is also added to signify the presence or absence of the storage slot in the tree. +A new field, `prev_counter`, is incorporated to the `ordered_storage_writes` to indicate whether each write has a preceding snap or write. Another field, `exists`, is also added to signify the presence or absence of the storage slot in the tree. -1. For each _snap_ at index _i_ in _public_data_snaps_: +1. For each `snap` at index `i` in `public_data_snaps`: - - Skip the remaining steps if it is empty or if its _override_counter_ is _0_. - - Locate the _write_ at _`ordered_storage_writes[storage_write_indices[i]]`_. + - Skip the remaining steps if it is empty or if its `override_counter` is `0`. + - Locate the `write` at `ordered_storage_writes[storage_write_indices[i]]`. - Verify the following: - - _`write.storage_slot == snap.storage_slot`_ - - _`write.counter == snap.override_counter`_ - - _`write.prev_counter == 0`_ - - Update the hints in _write_: - - _`write.prev_counter = 1`_ - - _`write.exists = snap.exists`_ + - `write.storage_slot == snap.storage_slot` + - `write.counter == snap.override_counter` + - `write.prev_counter == 0` + - Update the hints in `write`: + - `write.prev_counter = 1` + - `write.exists = snap.exists` - > The value _1_ can be utilized to signify a preceding _snap_, as this value can never serve as the counter of a _storage_write_. Because the _counter_start_ for the first public function call must be 1, the counters for all subsequent side effects should exceed this initial value. + > The value _1_ can be utilized to signify a preceding `snap`, as this value can never serve as the counter of a `storage_write`. Because the _counter_start_ for the first public function call must be 1, the counters for all subsequent side effects should exceed this initial value. -2. For each _write_ at index _i_ in _ordered_storage_writes_: +2. For each `write` at index `i` in `ordered_storage_writes`: - - Skip the remaining steps if its _next_counter_ is _0_. - - Locate the _next_write_ at _`ordered_storage_writes[next_storage_write_indices[i]]`_. + - Skip the remaining steps if its `next_counter` is `0`. + - Locate the `next_write` at `ordered_storage_writes[next_storage_write_indices[i]]`. - Verify the following: - - _`write.storage_slot == next_write.storage_slot`_ - - _`write.next_counter == next_write.counter`_ - - _`write.prev_counter == 0`_ - - Update the hints in _next_write_: - - _`next_write.prev_counter = write.counter`_ - - _`next_write.exists = write.exists`_ + - `write.storage_slot == next_write.storage_slot` + - `write.next_counter == next_write.counter` + - `write.prev_counter == 0` + - Update the hints in `next_write`: + - `next_write.prev_counter = write.counter` + - `next_write.exists = write.exists` -3. Following the previous two steps, verify that all non-empty writes in _ordered_storage_writes_ have a non-zero _prev_counter_. +3. Following the previous two steps, verify that all non-empty writes in `ordered_storage_writes` have a non-zero `prev_counter`. #### Verifying storage reads. A storage read can be reading: -- An uninitialized storage slot: the value is zero. There isn't a leaf in the public data tree representing its storage slot, nor in the _storage_writes_. +- An uninitialized storage slot: the value is zero. There isn't a leaf in the public data tree representing its storage slot, nor in the `storage_writes`. - An existing storage slot: written in a prior successful transaction. The value being read is the value in the public data tree. -- An updated storage slot: initialized or updated in the current transaction. The value being read is in a _storage_write_. +- An updated storage slot: initialized or updated in the current transaction. The value being read is in a `storage_write`. -For each non-empty _read_ at index _i_ in _ordered_storage_reads_, it must satisfy one of the following conditions: +For each non-empty `read` at index `i` in `ordered_storage_reads`, it must satisfy one of the following conditions: -1. If reading an uninitialized or an existing storage slot, the value is in a _snap_: +1. If reading an uninitialized or an existing storage slot, the value is in a `snap`: - - Locate the _snap_ at _`public_data_snaps[persistent_read_hints[i]]`_. + - Locate the `snap` at `public_data_snaps[persistent_read_hints[i]]`. - Verify the following: - - _`read.storage_slot == snap.storage_slot`_ - - _`read.value == snap.value`_ - - _`(read.counter < snap.override_counter) | (snap.override_counter == 0)`_ - - If _`snap.exists == false`_: - - _`read.value == 0`_ + - `read.storage_slot == snap.storage_slot` + - `read.value == snap.value` + - `(read.counter < snap.override_counter) | (snap.override_counter == 0)` + - If `snap.exists == false`: + - `read.value == 0` - Depending on the value of the _exists_ flag in the snap, verify its presence or absence in the public data tree: + Depending on the value of the `exists` flag in the snap, verify its presence or absence in the public data tree: - - If _exists_ is true: + - If `exists` is true: - It must pass a membership check on the leaf. - - If _exists_ is false: - - It must pass a non-membership check on the low leaf. The preimage of the low leaf is at _`storage_read_low_leaf_preimages[i]`_. + - If `exists` is false: + - It must pass a non-membership check on the low leaf. The preimage of the low leaf is at `storage_read_low_leaf_preimages[i]`. - > The (non-)membership checks are executed against the root in _old_public_data_tree_snapshot_. The membership witnesses for the leaves are in _storage_read_membership_witnesses_, provided as [hints](#hints) through _private_inputs_. + > The (non-)membership checks are executed against the root in `old_public_data_tree_snapshot`. The membership witnesses for the leaves are in `storage_read_membership_witnesses`, provided as [hints](#hints) through `private_inputs`. -2. If reading an updated storage slot, the value is in a _storage_write_: +2. If reading an updated storage slot, the value is in a `storage_write`: - - Locates the _storage_write_ at _`ordered_storage_writes[transient_read_hints[i]]`_. + - Locates the `storage_write` at `ordered_storage_writes[transient_read_hints[i]]`. - Verify the following: - - _`read.storage_slot == storage_write.storage_slot`_ - - _`read.value == storage_write.value`_ - - _`read.counter > storage_write.counter`_ - - _`(read.counter < storage_write.next_counter) | (storage_write.next_counter == 0)`_ + - `read.storage_slot == storage_write.storage_slot` + - `read.value == storage_write.value` + - `read.counter > storage_write.counter` + - `(read.counter < storage_write.next_counter) | (storage_write.next_counter == 0)` - > A zero _next_counter_ indicates that the value is not written again in the transaction. + > A zero `next_counter` indicates that the value is not written again in the transaction. #### Updating the public data tree. -It updates the public data tree with the values in _storage_writes_. The _latest_root_ of the tree is _old_public_data_tree_snapshot.root_. +It updates the public data tree with the values in `storage_writes`. The `latest_root` of the tree is _old_public_data_tree_snapshot.root_. -For each non-empty _write_ at index _i_ in _ordered_storage_writes_, the circuit processes it base on its type: +For each non-empty `write` at index `i` in `ordered_storage_writes`, the circuit processes it base on its type: 1. Transient write. - If _`write.next_counter != 0`_, the same storage slot is written again by another storage write that occurs later in the same transaction. This transient _write_ can be ignored as the final state of the tree won't be affected by it. + If `write.next_counter != 0`, the same storage slot is written again by another storage write that occurs later in the same transaction. This transient `write` can be ignored as the final state of the tree won't be affected by it. 2. Updating an existing storage slot. - For a non-transient _write_ (_write.next_counter == 0_), if _`write.exists == true`_, it is updating an existing storage slot. The circuit does the following for such a write: + For a non-transient `write` (`write.next_counter == 0`), if `write.exists == true`, it is updating an existing storage slot. The circuit does the following for such a write: - Performs a membership check, where: - The leaf if for the existing storage slot. - - _`leaf.storage_slot = write.storage_slot`_ - - The old value is the value in a _snap_: - - _`leaf.value = public_data_snaps[public_data_snap_indices[i]].value`_ - - The index and the sibling path are in _storage_write_membership_witnesses_, provided as [hints](#hints) through _private_inputs_. - - The root is the _latest_root_ after processing the previous write. - - Derives the _latest_root_ for the _latest_public_data_tree_ with the updated leaf, where _`leaf.value = write.value`_. + - `leaf.storage_slot = write.storage_slot` + - The old value is the value in a `snap`: + - `leaf.value = public_data_snaps[public_data_snap_indices[i]].value` + - The index and the sibling path are in `storage_write_membership_witnesses`, provided as [hints](#hints) through `private_inputs`. + - The root is the `latest_root` after processing the previous write. + - Derives the `latest_root` for the `latest_public_data_tree` with the updated leaf, where `leaf.value = write.value`. 3. Creating a new storage slot. - For a non-transient _write_ (_write.next_counter == 0_), if _`write.exists == false`_, it is initializing a storage slot. The circuit adds it to a subtree: + For a non-transient `write` (`write.next_counter == 0`), if `write.exists == false`, it is initializing a storage slot. The circuit adds it to a subtree: - Perform a membership check on the low leaf in the _latest_public_data_tree_ and in the subtree. One check must succeed. - - The low leaf preimage is at _storage_write_low_leaf_preimages[i]_. - - The membership witness for the public data tree is at _storage_write_membership_witnesses[i]_. - - The membership witness for the subtree is at _subtree_membership_witnesses[i]_. - - The above are provided as [hints](#hints) through _private_inputs_. + - The low leaf preimage is at `storage_write_low_leaf_preimages[i]`. + - The membership witness for the public data tree is at `storage_write_membership_witnesses[i]`. + - The membership witness for the subtree is at `subtree_membership_witnesses[i]`. + - The above are provided as [hints](#hints) through `private_inputs`. - Update the low leaf to point to the new leaf: - - _`low_leaf.next_slot = write.storage_slot`_ - - _`low_leaf.next_index = old_public_data_tree_snapshot.next_available_leaf_index + number_of_new_leaves`_ - - If the low leaf is in the _latest_public_data_tree_, derive the _latest_root_ from the updated low leaf. - - If the low leaf is in the subtree, derive the _subtree_root_ from the updated low leaf. - - Append the new leaf to the subtree. Derive the _subtree_root_. - - Increment _number_of_new_leaves_ by 1. + - `low_leaf.next_slot = write.storage_slot` + - `low_leaf.next_index = old_public_data_tree_snapshot.next_available_leaf_index + number_of_new_leaves` + - If the low leaf is in the `latest_public_data_tree`, derive the `latest_root` from the updated low leaf. + - If the low leaf is in the subtree, derive the `subtree_root` from the updated low leaf. + - Append the new leaf to the subtree. Derive the `subtree_root`. + - Increment `number_of_new_leaves` by `1`. > The subtree and _number_of_new_leaves_ are initialized to empty and 0 at the beginning of the process. After all the storage writes are processed: - Batch insert the subtree to the public data tree. - - The insertion index is _`old_public_data_tree_snapshot.next_available_leaf_index`_. + - The insertion index is `old_public_data_tree_snapshot.next_available_leaf_index`. - Verify the following: - - _`latest_root == new_public_data_tree_snapshot.root`_ - - _`new_public_data_tree_snapshot.next_available_leaf_index == old_public_data_tree_snapshot.next_available_leaf_index + number_of_new_leaves`_ + - `latest_root == new_public_data_tree_snapshot.root` + - `new_public_data_tree_snapshot.next_available_leaf_index == old_public_data_tree_snapshot.next_available_leaf_index + number_of_new_leaves` ### Validating Public Inputs @@ -213,31 +217,31 @@ After all the storage writes are processed: 1. The following must align with the results after siloing, as verified in a [previous step](#siloing-values): - - _l2_to_l1_messages_ + - `l2_to_l1_messages` 2. The following must align with the results after ordering, as verified in a [previous step](#verifying-ordered-arrays): - - _note_hashes_ - - _nullifiers_ + - `note_hashes` + - `nullifiers` 3. The hashes and lengths for unencrypted logs are accumulated as follows: - Initialize _accumulated_logs_hash_ to be the _unencrypted_logs_hash_ within _[private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs].[accumulated_data](#accumulateddata)_. + Initialize `accumulated_logs_hash` to be the `unencrypted_logs_hash` within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel).[public_inputs].[accumulated_data](#accumulateddata). - For each non-empty _log_hash_ at index _i_ in _ordered_unencrypted_log_hashes_, which is provided as [hints](#hints), and the [ordering](#verifying-ordered-arrays) was verified against the [siloed hashes](#siloing-values) in previous steps: + For each non-empty _log_hash_ at index `i` in `ordered_unencrypted_log_hashes`, which is provided as [hints](#hints), and the [ordering](#verifying-ordered-arrays) was verified against the [siloed hashes](#siloing-values) in previous steps: - - _`accumulated_logs_hash = hash(accumulated_logs_hash, log_hash.hash)`_ - - _`accumulated_logs_length += log_hash.length`_ + - `accumulated_logs_hash = hash(accumulated_logs_hash, log_hash.hash)` + - `accumulated_logs_length += log_hash.length` - Check the values in the _public_inputs_ are correct: + Check the values in the `public_inputs` are correct: - - _`unencrypted_logs_hash == accumulated_logs_hash`_ - - _`unencrypted_log_preimages_length == accumulated_logs_length`_ + - `unencrypted_logs_hash == accumulated_logs_hash` + - `unencrypted_log_preimages_length == accumulated_logs_length` 4. The following is referenced and verified in a [previous step](#updating-the-public-data-tree): - - _old_public_data_tree_snapshot_ - - _new_public_data_tree_snapshot_ + - `old_public_data_tree_snapshot` + - `new_public_data_tree_snapshot` #### Verifying the transient accumulated data. @@ -245,146 +249,146 @@ It ensures that the transient accumulated data is empty. #### Verifying the constant data. -This section follows the same [process](./private-kernel-inner.md#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. -## Private Inputs +## `PrivateInputs` -### _PreviousKernel_ +### `PreviousKernel` -| Field | Type | Description | -| -------------------- | -------------------------------------------------------------------- | -------------------------------------------- | -| _public_inputs_ | _[PublicKernelPublicInputs](#public-inputs)_ | Public inputs of the proof. | -| _proof_ | _Proof_ | Proof of the kernel circuit. | -| _vk_ | _VerificationKey_ | Verification key of the kernel circuit. | -| _membership_witness_ | _[MembershipWitness](./private-kernel-initial.md#membershipwitness)_ | Membership witness for the verification key. | +| Field | Type | Description | +| -------------------- | --------------------------------------------------------------------- | -------------------------------------------- | +| `public_inputs` | [`PublicKernelPublicInputs`](#public-inputs) | Public inputs of the proof. | +| `proof` | `Proof` | Proof of the kernel circuit. | +| `vk` | `VerificationKey` | Verification key of the kernel circuit. | +| `membership_witness` | [`MembershipWitness`](./private-kernel-initial.mdx#membershipwitness) | Membership witness for the verification key. | ### _Hints_ Data that aids in the verifications carried out in this circuit: -| Field | Type | Description | -| ------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -| _note_hash_indices_ | [_field_; _C_] | Indices of _note_hashes_ for _note_hash_contexts_. _C_ equals the length of _note_hashes_. | -| _note_hash_hints_ | [_field_; _C_] | Indices of _note_hash_contexts_ for ordered _note_hashes_. _C_ equals the length of _note_hash_contexts_. | -| _nullifier_hints_ | [_field_; _C_] | Indices of _nullifier_contexts_ for ordered _nullifiers_. _C_ equals the length of _nullifier_contexts_. | -| _ordered_unencrypted_log_hashes_ | [_field_; _C_] | Ordered _unencrypted_log_hashes_. _C_ equals the length of _unencrypted_log_hashes_. | -| _unencrypted_log_hash_hints_ | [_field_; _C_] | Indices of _ordered_unencrypted_log_hashes_ for _unencrypted_log_hash_contexts_. _C_ equals the length of _unencrypted_log_hash_contexts_. | -| _ordered_storage_reads_ | [_[StorageReadContext](#storagereadcontext)_; _C_] | Ordered _storage_reads_. _C_ equals the length of _storage_reads_. | -| _storage_read_hints_ | [_field_; _C_] | Indices of reads for _ordered_storage_reads_. _C_ equals the length of _storage_reads_. | -| _ordered_storage_writes_ | [_[StorageWriteContext](#storagewritecontext)_; _C_] | Ordered _storage_writes_. _C_ equals the length of _storage_writes_. | -| _storage_write_hints_ | [_field_; _C_] | Indices of writes for _ordered_storage_writes_. _C_ equals the length of _storage_writes_. | -| _public_data_snaps_ | [_[PublicDataSnap](#publicdatasnap)_; _C_] | Data that aids verification of storage reads and writes. _C_ equals the length of _ordered_storage_writes_ + _ordered_storage_reads_. | -| _storage_write_indices_ | [_field_; _C_] | Indices of _ordered_storage_writes_ for _public_data_snaps_. _C_ equals the length of _public_data_snaps_. | -| _transient_read_hints_ | [_field_; _C_] | Indices of _ordered_storage_writes_ for transient reads. _C_ equals the length of _ordered_storage_reads_. | -| _persistent_read_hints_ | [_field_; _C_] | Indices of _ordered_storage_writes_ for persistent reads. _C_ equals the length of _ordered_storage_reads_. | -| _public_data_snap_indices_ | [_field_; _C_] | Indices of _public_data_snaps_ for persistent write. _C_ equals the length of _ordered_storage_writes_. | -| _storage_read_low_leaf_preimages_ | [_[PublicDataLeafPreimage](#publicdataleafpreimage)_; _C_] | Preimages for public data leaf. _C_ equals the length of _ordered_storage_writes_. | -| _storage_read_membership_witnesses_ | [_[MembershipWitness](./private-kernel-initial.md#membershipwitness)_; _C_] | Membership witnesses for persistent reads. _C_ equals the length of _ordered_storage_writes_. | -| _storage_write_low_leaf_preimages_ | [_[PublicDataLeafPreimage](#publicdataleafpreimage)_; _C_] | Preimages for public data. _C_ equals the length of _ordered_storage_writes_. | -| _storage_write_membership_witnesses_ | [_[MembershipWitness](./private-kernel-initial.md#membershipwitness)_; _C_] | Membership witnesses for public data tree. _C_ equals the length of _ordered_storage_writes_. | -| _subtree_membership_witnesses_ | [_[MembershipWitness](./private-kernel-initial.md#membershipwitness)_; _C_] | Membership witnesses for the public data subtree. _C_ equals the length of _ordered_storage_writes_. | +| Field | Type | Description | +| ------------------------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | +| `note_hash_indices` | `[field; C]` | Indices of `note_hashes` for `note_hash_contexts`. `C` equals the length of `note_hashes`. | +| `note_hash_hints` | `[field; C]` | Indices of `note_hash_contexts` for ordered `note_hashes`. `C` equals the length of `note_hash_contexts`. | +| `nullifier_hints` | `[field; C]` | Indices of _nullifier_contexts_ for ordered `nullifiers`. `C` equals the length of _nullifier_contexts_. | +| `ordered_unencrypted_log_hashes` | `[field; C]` | Ordered _unencrypted_log_hashes_. `C` equals the length of _unencrypted_log_hashes_. | +| `unencrypted_log_hash_hints` | `[field; C]` | Indices of `ordered_unencrypted_log_hashes` for _unencrypted_log_hash_contexts_. `C` equals the length of _unencrypted_log_hash_contexts_. | +| `ordered_storage_reads` | [`[StorageReadContext; C]`](#storagereadcontext) | Ordered `storage_reads`. `C` equals the length of `storage_reads`. | +| `storage_read_hints` | `[field; C]` | Indices of reads for `ordered_storage_reads`. `C` equals the length of `storage_reads`. | +| `ordered_storage_writes` | [`[StorageWriteContext; C]`](#storagewritecontext) | Ordered `storage_writes`. `C` equals the length of `storage_writes`. | +| `storage_write_hints` | `[field; C]` | Indices of writes for `ordered_storage_writes`. `C` equals the length of `storage_writes`. | +| `public_data_snaps` | [`[PublicDataSnap; C]`](#publicdatasnap) | Data that aids verification of storage reads and writes. `C` equals the length of `ordered_storage_writes` + `ordered_storage_reads`. | +| `storage_write_indices` | `[field; C]` | Indices of `ordered_storage_writes` for `public_data_snaps`. `C` equals the length of `public_data_snaps`. | +| `transient_read_hints` | `[field; C]` | Indices of `ordered_storage_writes` for transient reads. `C` equals the length of `ordered_storage_reads`. | +| `persistent_read_hints` | `[field; C]` | Indices of `ordered_storage_writes` for persistent reads. `C` equals the length of `ordered_storage_reads`. | +| `public_data_snap_indices` | `[field; C]` | Indices of `public_data_snaps` for persistent write. `C` equals the length of `ordered_storage_writes`. | +| `storage_read_low_leaf_preimages` | [`[PublicDataLeafPreimage; C]`](#publicdataleafpreimage) | Preimages for public data leaf. `C` equals the length of `ordered_storage_writes`. | +| `storage_read_membership_witnesses` | [`[MembershipWitness; C]`](./private-kernel-initial.mdx#membershipwitness) | Membership witnesses for persistent reads. `C` equals the length of `ordered_storage_writes`. | +| `storage_write_low_leaf_preimages` | [`[PublicDataLeafPreimage; C]`](#publicdataleafpreimage) | Preimages for public data. `C` equals the length of `ordered_storage_writes`. | +| `storage_write_membership_witnesses` | [`[MembershipWitness; C]`](./private-kernel-initial.mdx#membershipwitness) | Membership witnesses for public data tree. `C` equals the length of `ordered_storage_writes`. | +| `subtree_membership_witnesses` | [`[MembershipWitness; C]`](./private-kernel-initial.mdx#membershipwitness) | Membership witnesses for the public data subtree. `C` equals the length of `ordered_storage_writes`. | ## Public Inputs -### _ConstantData_ +### `ConstantData` -These are constants that remain the same throughout the entire transaction. Its format aligns with the _[ConstantData](./private-kernel-initial.md#constantdata)_ of the initial private kernel circuit. +These are constants that remain the same throughout the entire transaction. Its format aligns with the [ConstantData](./private-kernel-initial.mdx#constantdata) of the initial private kernel circuit. -### _AccumulatedData_ +### `AccumulatedData` Data accumulated during the execution of the transaction. -| Field | Type | Description | -| ---------------------------------- | ------------------------------- | ----------------------------------------------------------- | -| _note_hashes_ | [_field_; _C_] | Note hashes created in the transaction. | -| _nullifiers_ | [_field_; _C_] | Nullifiers created in the transaction. | -| _l2_to_l1_messages_ | [_field_; _C_] | L2-to-L1 messages created in the transaction. | -| _unencrypted_logs_hash_ | _field_ | Hash of the accumulated unencrypted logs. | -| _unencrypted_log_preimages_length_ | _field_ | Length of all unencrypted log preimages. | -| _encrypted_logs_hash_ | _field_ | Hash of the accumulated encrypted logs. | -| _encrypted_log_preimages_length_ | _field_ | Length of all encrypted log preimages. | -| _encrypted_note_preimages_hash_ | _field_ | Hash of the accumulated encrypted note preimages. | -| _encrypted_note_preimages_length_ | _field_ | Length of all encrypted note preimages. | -| _old_public_data_tree_snapshot_ | _[TreeSnapshot](#treesnapshot)_ | Snapshot of the public data tree prior to this transaction. | -| _new_public_data_tree_snapshot_ | _[TreeSnapshot](#treesnapshot)_ | Snapshot of the public data tree after this transaction. | - -> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. - -### _TransientAccumulatedData_ - -| Field | Type | Description | -| --------------------------- | --------------------------------------------------------------------------------- | ------------------------------------------------------ | -| _note_hash_contexts_ | [_[NoteHashContext](./private-kernel-initial.md#notehashcontext)_; _C_] | Note hashes with extra data aiding verification. | -| _nullifier_contexts_ | [_[NullifierContext](./private-kernel-initial.md#nullifiercontext)_; _C_] | Nullifiers with extra data aiding verification. | -| _l2_to_l1_message_contexts_ | [_[L2toL1MessageContext](./private-kernel-initial.md#l2tol1messagecontext)_; _C_] | L2-to-l1 messages with extra data aiding verification. | -| _storage_reads_ | [_[StorageRead](#storageread)_; _C_] | Reads of the public data. | -| _storage_writes_ | [_[StorageWrite](#storagewrite)_; _C_] | Writes of the public data. | -| _public_call_requests_ | [_[CallRequest](./private-kernel-initial.md#callrequest)_; _C_] | Requests to call publics functions. | - -> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. +| Field | Type | Description | +| ---------------------------------- | --------------------------------- | ----------------------------------------------------------- | +| `note_hashes` | `[field; C]` | Note hashes created in the transaction. | +| `nullifiers` | `[field; C]` | Nullifiers created in the transaction. | +| `l2_to_l1_messages` | `[field; C]` | L2-to-L1 messages created in the transaction. | +| `unencrypted_logs_hash` | `field` | Hash of the accumulated unencrypted logs. | +| `unencrypted_log_preimages_length` | `field` | Length of all unencrypted log preimages. | +| `encrypted_logs_hash` | `field` | Hash of the accumulated encrypted logs. | +| `encrypted_log_preimages_length` | `field` | Length of all encrypted log preimages. | +| `encrypted_note_preimages_hash` | `field` | Hash of the accumulated encrypted note preimages. | +| `encrypted_note_preimages_length` | `field` | Length of all encrypted note preimages. | +| `old_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree prior to this transaction. | +| `new_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree after this transaction. | + +> The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. + +### `TransientAccumulatedData` + +| Field | Type | Description | +| --------------------------- | -------------------------------------------------------------------------------- | ------------------------------------------------------ | +| `note_hash_contexts` | [`[NoteHashContext; C]`](./private-kernel-initial.mdx#notehashcontext) | Note hashes with extra data aiding verification. | +| `nullifier_contexts` | [`[NullifierContext; C]`](./private-kernel-initial.mdx#nullifiercontext) | Nullifiers with extra data aiding verification. | +| `l2_to_l1_message_contexts` | [`[L2toL1MessageContext; C]`](./private-kernel-initial.mdx#l2tol1messagecontext) | L2-to-l1 messages with extra data aiding verification. | +| `storage_reads` | [`[StorageRead; C]`](#storageread) | Reads of the public data. | +| `storage_writes` | [`[StorageWrite; C]`](#storagewrite) | Writes of the public data. | +| `public_call_requests` | [`[CallRequest; C]`](./private-kernel-initial.mdx#callrequest) | Requests to call publics functions. | + +> The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. ## Types -### _TreeSnapshot_ +### `TreeSnapshot` -| Field | Type | Description | -| --------------------------- | ----- | --------------------------------- | -| _root_ | field | Root of the tree. | -| _next_available_leaf_index_ | field | The index to insert new value to. | +| Field | Type | Description | +| --------------------------- | ------- | --------------------------------- | +| `root` | `field` | Root of the tree. | +| `next_available_leaf_index` | `field` | The index to insert new value to. | -### _StorageRead_ +### `StorageRead` | Field | Type | Description | | ------------------ | -------------- | ----------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract. | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | Value read from the storage slot. | -| _counter_ | _field_ | Counter at which the read happened. | +| `contract_address` | `AztecAddress` | Address of the contract. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | Value read from the storage slot. | +| `counter` | `field` | Counter at which the read happened. | -### _StorageWrite_ +### `StorageWrite` | Field | Type | Description | | ------------------ | -------------- | -------------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract. | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | New value written to the storage slot. | -| _counter_ | _field_ | Counter at which the write happened. | +| `contract_address` | `AztecAddress` | Address of the contract. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | New value written to the storage slot. | +| `counter` | `field` | Counter at which the write happened. | -### _StorageReadContext_ +### `StorageReadContext` | Field | Type | Description | | ------------------ | -------------- | ----------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract. | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | Value read from the storage slot. | -| _counter_ | _field_ | Counter at which the read happened. | +| `contract_address` | `AztecAddress` | Address of the contract. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | Value read from the storage slot. | +| `counter` | `field` | Counter at which the read happened. | -### _StorageWriteContext_ +### `StorageWriteContext` | Field | Type | Description | | ------------------ | -------------- | ---------------------------------------------------------------------- | -| _contract_address_ | _AztecAddress_ | Address of the contract. | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | New value written to the storage slot. | -| _counter_ | _field_ | Counter at which the write happened. | -| _prev_counter_ | _field_ | Counter of the previous write to the storage slot. | -| _next_counter_ | _field_ | Counter of the next write to the storage slot. | -| _exists_ | _bool_ | A flag indicating whether the storage slot is in the public data tree. | +| `contract_address` | `AztecAddress` | Address of the contract. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | New value written to the storage slot. | +| `counter` | `field` | Counter at which the write happened. | +| `prev_counter` | `field` | Counter of the previous write to the storage slot. | +| `next_counter` | `field` | Counter of the next write to the storage slot. | +| `exists` | `bool` | A flag indicating whether the storage slot is in the public data tree. | -### _PublicDataSnap_ +### `PublicDataSnap` | Field | Type | Description | | ------------------ | ------- | ------------------------------------------------------------------------ | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | Value of the storage slot. | -| _override_counter_ | _field_ | Counter at which the _storage_slot_ is first written in the transaction. | -| _exists_ | _bool_ | A flag indicating whether the storage slot is in the public data tree. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | Value of the storage slot. | +| `override_counter` | `field` | Counter at which the `storage_slot` is first written in the transaction. | +| `exists` | `bool` | A flag indicating whether the storage slot is in the public data tree. | -### _PublicDataLeafPreimage_ +### `PublicDataLeafPreimage` | Field | Type | Description | | -------------- | ------- | ------------------------------ | -| _storage_slot_ | field | Storage slot. | -| _value_ | field | Value of the storage slot. | -| _next_slot_ | _field_ | Storage slot of the next leaf. | -| _next_index_ | _field_ | Index of the next leaf. | +| `storage_slot` | `field` | Storage slot. | +| `value` | `field` | Value of the storage slot. | +| `next_slot` | `field` | Storage slot of the next leaf. | +| `next_index` | `field` | Index of the next leaf. | diff --git a/yellow-paper/docs/constants.md b/yellow-paper/docs/constants.md new file mode 100644 index 00000000000..496eb93b1c5 --- /dev/null +++ b/yellow-paper/docs/constants.md @@ -0,0 +1,124 @@ +--- +title: Constants +--- + +:::warning Draft +All of these constants are subject to change, pending benchmarking, optimizations, and general protocol changes. +::: + +## Tree Constants + +See also: [state](./state/index.md). + +:::warning Tree Epochs +Note: we might introduce tree epochs, which will reduce the height of each epoch's tree, and means we don't need to estimate future network state growth in advance. +::: + + +| Name | Value | Description | +|---|---|---| +| `ARCHIVE_TREE_HEIGHT` | `27` | Prudent justification: 1 block/min \* 200 years ~= 2^27 blocks | +| `NOTE_HASH_TREE_HEIGHT` | `39` | Prudent justification: 10 tx/s \* 8 notes/tx \* 200 years. | +| `NULLIFIER_TREE_HEIGHT` | `42` | Prudent justification: \[Number of notes _ 2 (to allow a huge buffer for initialization nullifiers and other nullifier usage)] + \[ 2 _ Estimated number of contracts (to allow a huge buffer for contract class & instance nullifiers) ]. An estimate for the number of contracts ever to be deployed is debatable. | +| `PUBLIC_DATA_TREE_HEIGHT` | `39` | Prudent justification: 10 tx/s \* 8 storage slots/tx \* 200 years. | +| `L1_TO_L2_MESSAGE_TREE` | `33` | Prudent justification: 10 tx/s \* 10% of txs consuming a message \* 200 years. | +| `PRIVATE_FUNCTION_TREE_HEIGHT` | `5` | Note: this means a smart contract can only declare `2 ** 5 = 32` private functions. | + +For all trees, an empty leaf has value `0`. + +For all indexed merkle trees, the 0th leaf is the "zero predecessor leaf" with leaf preimage `{ value: 0, next_index: 0, next_value: 0}`. + +## Circuit Constants + +:::warning +Note: "per call" values might be much more flexible, once the data bus is introduced. These numbers are finger-in-the-air estimates of values that might be possible with the data bus. Benchmarking will be needed. +::: + +The statically-sized nature the kernel & rollup circuits will restrict the quantity of 'side effects' that a single call or transaction can create. + +### Per Call + + +| Name | Value | Description | +|---|---|---| +| `MAX_NEW_COMMITMENTS_PER_CALL` | 128 | +| `MAX_NEW_NULLIFIERS_PER_CALL` | 128 | +| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL` | 32 | +| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL` | 32 | +| `MAX_NEW_L2_TO_L1_MSGS_PER_CALL` | 4 | +| `MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL` | 128 | +| `MAX_PUBLIC_DATA_READS_PER_CALL` | 128 | +| `MAX_READ_REQUESTS_PER_CALL` | 128 | +| `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL` | 1 | TODO: we shouldn't need this, given the reset circuit. | + +### Per Tx + + +| Name | Value | Description | +|---|---|---| +| `MAX_NEW_COMMITMENTS_PER_TX` | 128 | +| `MAX_NEW_NULLIFIERS_PER_TX` | 128 | +| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX` | 32 | +| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX` | 32 | +| `MAX_NEW_L2_TO_L1_MSGS_PER_TX` | 16 | +| `MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX` | 16 | +| `MAX_PUBLIC_DATA_READS_PER_TX` | 16 | +| `MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX` | 4 | +| `MAX_READ_REQUESTS_PER_TX` | 128 | TODO: we shouldn't need this, given the reset circuit. | +| `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX` | 4 | TODO: we shouldn't need this, given the reset circuit. | +| `NUM_ENCRYPTED_LOGS_HASHES_PER_TX` | 1 | +| `NUM_UNENCRYPTED_LOGS_HASHES_PER_TX` | 1 | + +## Block constants + +## Genesis Constants + +### Genesis Addresses + +:::warning +TODO: consider whether these addresses should be 'nice', small values, or whether these addresses should be derived in the same way as all other addresses (but with a deployer_address of `0x00`). + +TODO: some of these contracts will be baked into genesis. Some of them might need to be deployed as part of the first network 'upgrade', and so might end up being removed from this section. This is still being discussed. +::: + +| Name | Value | Description | +| --------------------------------------- | ------- | ------------------------------------------------------ | +| Space reserved for precompile addresses | | | +| `CONTRACT_CLASS_REGISTERER_ADDRESS` | 0x10000 | See [here](./contract-deployment/classes.md#genesis) | +| `CONTRACT_INSTANCE_DEPLOYER_ADDRESS` | 0x10001 | See [here](./contract-deployment/instances.md#genesis) | +| `FEE_JUICE_ADDRESS` | 0x10002 | TODO: consider at what stage this should be deployed. | + +### Genesis Archive Tree + +The 0th leaf of the archive tree will be hard-coded at genesis to be an empty collection of state trees and an empty previous header. + + + +### Genesis Nullifiers + +| Name | Value | Description | +| ------------------------------------------------------------------------------------ | ----- | ----------------------------------------------------- | +| The zero predecessor leaf. | TODO | Needed to make an indexed merkle tree work. | +| The zero predecessor leaf index. | `0` | Needed to make an indexed merkle tree work. | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_CLASS_ID_NULLIFIER_OF_CONTRACT_CLASS_REGISTERER` | `1` | See [here](./contract-deployment/classes.md#genesis). | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_DEPLOYMENT_NULLIFIER_OF_CONTRACT_CLASS_REGISTERER` | `2` | See [here](./contract-deployment/classes.md#genesis). | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_CLASS_ID_NULLIFIER_OF_CONTRACT_INSTANCE_DEPLOYER` | `3` | See [here](./contract-deployment/classes.md#genesis). | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_DEPLOYMENT_NULLIFIER_OF_CONTRACT_INSTANCE_DEPLOYER` | `4` | See [here](./contract-deployment/classes.md#genesis). | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_CLASS_ID_NULLIFIER_OF_FEE_JUICE_CONTRACT` | `5` | See [here](./contract-deployment/classes.md#genesis). | +| `GENESIS_NULLIFIER_LEAF_INDEX_OF_DEPLOYMENT_NULLIFIER_OF_FEE_JUICE_CONTRACT` | `6` | See [here](./contract-deployment/classes.md#genesis). | + +:::warning +TODO: hard-code the actual nullifier values, once the code has been frozen. +::: + + + +These verbose names are designed to get more specific from left to right. + +## Precompile Constants + +See the [precompiles](./addresses-and-keys/precompiles.md#constants) section. + +## Hashing constants + +See the [hashing] section. diff --git a/yellow-paper/docs/contract-deployment/classes.md b/yellow-paper/docs/contract-deployment/classes.md index 7069d497479..aff9bdc64ad 100644 --- a/yellow-paper/docs/contract-deployment/classes.md +++ b/yellow-paper/docs/contract-deployment/classes.md @@ -12,9 +12,9 @@ Read the following discussions for additional context: - [Abstracting contract deployment](https://forum.aztec.network/t/proposal-abstracting-contract-deployment/2576) - [Implementing contract upgrades](https://forum.aztec.network/t/implementing-contract-upgrades/2570) - [Contract classes, upgrades, and default accounts](https://forum.aztec.network/t/contract-classes-upgrades-and-default-accounts/433) -::: + ::: -## Structure +## `ContractClass` The structure of a contract class is defined as: @@ -41,7 +41,7 @@ public_bytecode_commitment = calculate_commitment(packed_public_bytecode) contract_class_id = pedersen([artifact_hash, private_functions_root, public_bytecode_commitment], GENERATOR__CLASS_IDENTIFIER_V1) ``` -Private Functions are hashed into Function Leaves before being merkleized into a tree of height `FUNCTION_TREE_HEIGHT=5`. Empty leaves have value `0`. A poseidon hash is used. The AVM public bytecode commitment is calculated as [defined in the Public VM section](../public-vm/bytecode-validation-circuit.md#committed-representation). +Private Functions are hashed into Function Leaves before being merkleized into a tree of height [`FUNCTION_TREE_HEIGHT`](../constants.md#tree-constants). Empty leaves have value `0`. A poseidon hash is used. The AVM public bytecode commitment is calculated as [defined in the Public VM section](../public-vm/bytecode-validation-circuit.md#committed-representation). ### Private Function @@ -62,19 +62,19 @@ Also note the lack of commitment to the function compilation artifact. Even thou Even though not enforced by the protocol, it is suggested for the `artifact_hash` to follow this general structure, in order to be compatible with the definition of the [`broadcast` function below](#broadcast). ``` -private_functions_artifact_leaves = artifact.private_functions.map(fn => +private_functions_artifact_leaves = artifact.private_functions.map(fn => sha256(fn.selector, fn.metadata_hash, sha256(fn.private_bytecode)) ) private_functions_artifact_tree_root = merkleize(private_functions_artifact_leaves) -unconstrained_functions_artifact_leaves = artifact.unconstrained_functions.map(fn => +unconstrained_functions_artifact_leaves = artifact.unconstrained_functions.map(fn => sha256(fn.selector, fn.metadata_hash, sha256(fn.unconstrained_bytecode)) ) unconstrained_functions_artifact_tree_root = merkleize(unconstrained_functions_artifact_leaves) artifact_hash = sha256( private_functions_artifact_tree_root, - unconstrained_functions_artifact_tree_root, + unconstrained_functions_artifact_tree_root, artifact_metadata, ) ``` @@ -125,7 +125,7 @@ function register( artifact_hash: Field, private_functions_root: Field, packed_public_bytecode: Field[], -) +) assert is_valid_packed_public_bytecode(packed_public_bytecode) version = 1 @@ -142,15 +142,13 @@ Note that emitting the `contract_class_id` as a nullifier (the `contract_class_i ### Genesis -The `ContractClassRegisterer` will need to exist from the genesis of the Aztec Network, otherwise nothing will ever be publicly deployable to the network. The Class Nullifier for the `ContractClassRegisterer` contract will be pre-inserted into the genesis nullifier tree at leaf index `GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_CLASS_REGISTERER_CLASS_ID_NULLIFIER=1`. The canonical instance will be deployed at `CONTRACT_CLASS_REGISTERER_ADDRESS=0x10000`, and its Deployment Nullifier will be inserted at `GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_CLASS_REGISTERER_DEPLOYMENT_NULLIFIER=2`. - - +The `ContractClassRegisterer` will need to exist from the genesis of the Aztec Network, otherwise nothing will ever be publicly deployable to the network. The Class Nullifier for the `ContractClassRegisterer` contract will be pre-inserted into the genesis nullifier tree at leaf index [`GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_CLASS_REGISTERER_CLASS_ID_NULLIFIER`](../constants.md#genesis-constants). The canonical instance will be deployed at [`CONTRACT_CLASS_REGISTERER_ADDRESS`](../constants.md#genesis-constants), and its Deployment Nullifier will be inserted at [`GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_CLASS_REGISTERER_DEPLOYMENT_NULLIFIER`](../constants.md#genesis-constants). ### Broadcast -The `ContractClassRegisterer` has an additional private `broadcast` functions that can be used for broadcasting on-chain the bytecode, both ACIR and Brillig, for private functions and unconstrained in the contract. Any user can freely call this function. Given that ACIR and Brillig [do not have a circuit-friendly commitment](../bytecode/index.md), it is left up to nodes to perform this check. +The `ContractClassRegisterer` has an additional private `broadcast` functions that can be used for broadcasting on-chain the bytecode, both ACIR and Brillig, for private functions and unconstrained in the contract. Any user can freely call this function. Given that ACIR and Brillig [do not have a circuit-friendly commitment](../bytecode/index.md), it is left up to nodes to perform this check. Broadcasted contract artifacts that do not match with their corresponding `artifact_hash`, or that reference a `contract_class_id` that has not been broadcasted, can be safely discarded. diff --git a/yellow-paper/docs/contract-deployment/instances.md b/yellow-paper/docs/contract-deployment/instances.md index 9d5e333824d..eb31836761f 100644 --- a/yellow-paper/docs/contract-deployment/instances.md +++ b/yellow-paper/docs/contract-deployment/instances.md @@ -1,5 +1,7 @@ # Contract instances + + A contract instance is a concrete deployment of a [contract class](./classes.md). A contract instance always references a contract class, which dictates what code it executes when called. A contract instance has state (both private and public), as well as an address that acts as its identifier. A contract instance can be called into. ## Requirements @@ -9,7 +11,7 @@ A contract instance is a concrete deployment of a [contract class](./classes.md) - A user calling into an address must be able to prove that it has not been deployed. This allows the executor to prove that a given call in a transaction is unsatisfiable and revert accordingly. - A user should be able to privately call into a contract without publicly deploying it. This allows private applications to deploy contracts without leaking information about their usage. -## `ContractInstance` structure +## `ContractInstance` The structure of a contract instance is defined as: @@ -32,7 +34,7 @@ Contract instances have a `version` field that identifies the schema of the inst ### Address -The address of the contract instance is computed as the hash of the elements in the structure above, as defined in [the addresses and keys section](../addresses-and-keys/specification.md#address). This computation is deterministic, which allows any user to precompute the expected deployment address of their contract, including account contracts. +The address of the contract instance is computed as the hash of the elements in the structure above, as defined in [the addresses and keys section](../addresses-and-keys/address.md#address). This computation is deterministic, which allows any user to precompute the expected deployment address of their contract, including account contracts. ### Deployer @@ -75,7 +77,7 @@ Contract constructors are not enshrined in the protocol, but handled at the appl These checks are embedded in the application circuits themselves. The constructor emits an Initialization Nullifier when it is invoked, which prevents it from being called more than once. The constructor code must also check that its own selector and the arguments for the call match the ones in the address preimage, which are supplied via an oracle call. -All non-constructor functions in the contract should require a merkle membership proof for the Initialization Nullifier, to prevent them from being called before the constructor is invoked. Nevertheless, a contract may choose to allow some functions to be called before initialization, such as in the case of [Diversified and Stealth account contracts](../addresses-and-keys/diversified-and-stealth.md). +All non-constructor functions in the contract should require a merkle membership proof for the Initialization Nullifier, to prevent them from being called before the constructor is invoked. Nevertheless, a contract may choose to allow some functions to be called before initialization, such as in the case of [Diversified and Stealth account contracts](../addresses-and-keys/diversified-and-stealth.md). Removing constructors from the protocol itself simplifies the kernel circuit, and decoupling Initialization from Public Deployments allows users to keep contract instances private if they wish to do so. @@ -101,16 +103,16 @@ The pseudocode for the process described above is the following: ``` function deploy ( - salt: Field, - contract_class_id: Field, - initialization_hash: Field, - portal_contract_address: Field, - public_keys_hash: Field, + salt: Field, + contract_class_id: Field, + initialization_hash: Field, + portal_contract_address: Field, + public_keys_hash: Field, universal_deploy?: boolean, ) assert nullifier_exists silo(contract_class_id, ContractClassRegisterer) assert is_valid_eth_address(portal_contract_address) - + deployer = if universal_deploy then zero else msg_sender version = 1 address = compute_address(version, salt, deployer, contract_class_id, initialization_hash, portal_contract_address, public_keys_hash) @@ -126,9 +128,7 @@ The `ContractInstanceDeployer` contract provides two implementations of the `dep ### Genesis -The `ContractInstanceDeployer` will need to exist from the genesis of the Aztec Network, otherwise nothing will ever be deployable to the network. The Class Nullifier for the `ContractInstanceDeployer` contract will be pre-inserted into the genesis nullifier tree at leaf index `GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_INSTANCE_DEPLOYER_CLASS_ID_NULLIFIER=3`. The canonical instance will be deployed at `CONTRACT_INSTANCE_DEPLOYER_ADDRESS=0x10001`, and its Deployment Nullifier will be inserted at `GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_INSTANCE_DEPLOYER_DEPLOYMENT_NULLIFIER=4`. - - +The `ContractInstanceDeployer` will need to exist from the genesis of the Aztec Network, otherwise nothing will ever be deployable to the network. The Class Nullifier for the `ContractInstanceDeployer` contract will be pre-inserted into the genesis nullifier tree at leaf index [`GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_INSTANCE_DEPLOYER_CLASS_ID_NULLIFIER`](../constants.md#genesis-constants). The canonical instance will be deployed at [`CONTRACT_INSTANCE_DEPLOYER_ADDRESS`](../constants.md#genesis-constants), and its Deployment Nullifier will be inserted at [`GENESIS_NULLIFIER_LEAF_INDEX_OF_CONTRACT_INSTANCE_DEPLOYER_DEPLOYMENT_NULLIFIER`](../constants.md#genesis-constants). @@ -140,9 +140,11 @@ The Kernel Circuit, both private and public, is responsible for verifying that t - The [function selector](./classes.md#private-function) being executed is part of the `contract_class_id`, verified via a Merkle membership proof of the selector in the functions tree of the Contract Class. Specific to private functions: + - The hash of the `verification_key` matches the `vk_hash` defined in the corresponding [Private Function](./classes.md#private-function) for the Contract Class. Specific to public functions: + - The bytecode loaded by the [AVM](../public-vm/avm.md) for the contract matches the `bytecode_commitment` in the contract class, verified using the [bytecode validation circuit](../public-vm/bytecode-validation-circuit.md). - The contract Deployment Nullifier has been emitted, or prove that it hasn't, in which case the transaction is expected to revert. This check is done via a merkle (non-)membership proof of the Deployment Nullifier. Note that a public function should be callable in the same transaction in which its contract Deployment Nullifier was emitted. @@ -172,4 +174,4 @@ While it is appealing to allow a user to privately create a new contract instanc This approach requires that constructors are only invoked as part of Public Deployment, so constructors would require an additional check for `msg_sender` being the canonical `ContractInstanceDeployer`. Furthermore, to ensure that an instance constructor is properly run, the `ContractInstanceDeployer` would need to know the selector for the instance constructor, which now needs to be part of the Contract Class, re-enshrining it into the protocol. Last, being able to keep agreements (contracts) private among their parties is commonplace in the traditional world, so there is a compelling argument for keeping this requirement. -Alternatively, we could remove constructor abstraction altogether, and have the Private Kernel Circuit check for the Deployment Nullifier, much like the Public Kernel Circuit does. However, this hurts Diversified and Stealth account contracts, which now require an explicit deployment and cannot be used directly. \ No newline at end of file +Alternatively, we could remove constructor abstraction altogether, and have the Private Kernel Circuit check for the Deployment Nullifier, much like the Public Kernel Circuit does. However, this hurts Diversified and Stealth account contracts, which now require an explicit deployment and cannot be used directly. diff --git a/docs/docs/developers/contracts/resources/main.md b/yellow-paper/docs/cryptography/hashing/hashing.md similarity index 100% rename from docs/docs/developers/contracts/resources/main.md rename to yellow-paper/docs/cryptography/hashing/hashing.md diff --git a/docs/docs/developers/contracts/resources/style_guide.md b/yellow-paper/docs/cryptography/hashing/pedersen.md similarity index 100% rename from docs/docs/developers/contracts/resources/style_guide.md rename to yellow-paper/docs/cryptography/hashing/pedersen.md diff --git a/yellow-paper/docs/cryptography/index.md b/yellow-paper/docs/cryptography/index.md new file mode 100644 index 00000000000..6cebf78ff71 --- /dev/null +++ b/yellow-paper/docs/cryptography/index.md @@ -0,0 +1,8 @@ +# Cryptography + +:::note +This section only comes at the beginning because it contains foundational cryptographic definitions that other sections use. +It's not recommended that you read this section first, because you'll probably give up before getting to the interesting sections. +::: + + diff --git a/yellow-paper/docs/cryptography/merkle-trees.md b/yellow-paper/docs/cryptography/merkle-trees.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/yellow-paper/docs/cryptography/proving-system/data-bus.md b/yellow-paper/docs/cryptography/proving-system/data-bus.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/yellow-paper/docs/cryptography/protocol-overview.md b/yellow-paper/docs/cryptography/proving-system/overview.md similarity index 99% rename from yellow-paper/docs/cryptography/protocol-overview.md rename to yellow-paper/docs/cryptography/proving-system/overview.md index 565da914b17..f7f786a257e 100644 --- a/yellow-paper/docs/cryptography/protocol-overview.md +++ b/yellow-paper/docs/cryptography/proving-system/overview.md @@ -122,4 +122,4 @@ To batch-verify multiple opening proofs, we use the technique articulated in the The following block diagrams describe the components used by the client-side and server-side Provers when computing client proofs and rollup proofs respectively. -![proof-system-components](../cryptography/images/proof-system-components.png) +![proof-system-components](../images/proof-system-components.png) diff --git a/yellow-paper/docs/cryptography/performance-targets.md b/yellow-paper/docs/cryptography/proving-system/performance-targets.md similarity index 95% rename from yellow-paper/docs/cryptography/performance-targets.md rename to yellow-paper/docs/cryptography/proving-system/performance-targets.md index 27a549310de..e6d79df5028 100644 --- a/yellow-paper/docs/cryptography/performance-targets.md +++ b/yellow-paper/docs/cryptography/proving-system/performance-targets.md @@ -22,7 +22,7 @@ The following is a list of the relevant properties that affect the performance o - Time to compute a 2-to-1 rollup proof - Memory required to compute a 2-to-1 rollup proof - | process | percent of block production time allocated to process | @@ -62,7 +62,7 @@ These are very rough estimates that could use further evaluation and validation! ### Proof size -The MVP wishes to target a tx through put of 10 tx per second. +The MVP wishes to target a tx throughput of 10 txs per second. Each Aztec node (not sequencer/prover, just a regular node that is sending transactions) needs to download `10*proof_size` bytes of data to keep track of the mempool. However, this is the _best case_ scenario. @@ -84,7 +84,7 @@ To support 100 transactions per second we would require a proof size of $8$ kilo The critical UX factor. To measure prover time for a transaction, we must first define a baseline transaction we wish to measure and the execution environment of the Prover. -As we build+refine our MVP, we want to avoid optimising the best-case scenario (i.e. the most basic tx type, a token transfer). Instead we want to ensure that transactions of a "moderate" complexity are possible with consuer hardware. +As we build+refine our MVP, we want to avoid optimising the best-case scenario (i.e. the most basic tx type, a token transfer). Instead we want to ensure that transactions of a "moderate" complexity are possible with consumer hardware. As a north star, we consider a private swap, and transpose it into an Aztec contract. diff --git a/yellow-paper/docs/cross-chain-communication/da.md b/yellow-paper/docs/data-publication-and-availability/index.md similarity index 99% rename from yellow-paper/docs/cross-chain-communication/da.md rename to yellow-paper/docs/data-publication-and-availability/index.md index fe94d32b4f3..4e5aed122a5 100644 --- a/yellow-paper/docs/cross-chain-communication/da.md +++ b/yellow-paper/docs/data-publication-and-availability/index.md @@ -22,7 +22,7 @@ Security is often used quite in an unspecific manner, "good" security etc, witho - **Liveness**: Eventually something good will happen. - **Safety**: Nothing bad will happen. -::: + ::: In the context of blockchain, this _security_ is defined by the confirmation rule, while this can be chosen individually by the user, our validating light node (L1 bridge) can be seen as a user, after all, it's "just" another node. For the case of a validity proof based blockchain, a good confirmation rule should satisfy the following sub-properties (inspired by [Sreeram's framing](https://twitter.com/sreeramkannan/status/1683735050897207296)): @@ -43,6 +43,8 @@ In particular, we will be looking at what is required to give observers (nodes) ## Quick Catch-up + + A rollup is broadly speaking a blockchain that put its blocks on some other chain (the host) to make them available to its nodes. Most rollups have a contract on this host blockchain which validates its state transitions (through fault proofs or validity proofs) taking the role of a full-validating light-node, increasing the accessibility of running a node on the rollup chain, making any host chain node indirectly validate its state. With its state being validated by the host chain, the security properties can eventually be enforced by the host-chain if the rollup chain itself is not progressing. Bluntly, the rollup is renting security from the host. The essential difference between a L1 and a rollup then comes down to who are required for block production (liveness) and to convince the validating light-node (security), for the L1 it is the nodes of the L1, and for the Rollup the nodes of its host (eventually). This in practice means that we can get some better properties for how easy it is to get sufficient assurance that no trickery is happening. @@ -134,7 +136,7 @@ While the committee is small, it seems like they can ensure honesty through the It is not fully clear how often blocks would be relayed to the hotshot contract for consumption by our rollup, but the team says it should be frequent. Cost is estimated to be ~400K gas. -## Aztec Specific Data +## Aztec-specific Data As part of figuring out the data throughput requirements, we need to know what data we need to publish. In Aztec we have a bunch of data with varying importance; some being important to **everyone** and some being important to **someone**. @@ -216,6 +218,8 @@ For every throughput column, we insert 3 marks, for everyone, someone and the to > **Disclaimer**: Remember that these fractions for available space are pulled out of my ass. + + With these numbers at hand, we can get an estimate of our throughput in transactions based on our storage medium. ## One or multiple data layers? diff --git a/yellow-paper/docs/decentralization/block-production.md b/yellow-paper/docs/decentralization/block-production.md index 88195545bb3..f554c304865 100644 --- a/yellow-paper/docs/decentralization/block-production.md +++ b/yellow-paper/docs/decentralization/block-production.md @@ -27,9 +27,9 @@ We should probably introduce the PXE somewhere - **CPU**: Help - **Network**: 40KB for a transaction with proof (see [P2P network](./p2p-network.md#network-bandwidth)). Assuming gossiping grows the data upload/download 10x, ~400KB per tx. With 10 tx/s that's 4MB/s or 32mb/s. -- **Storage**: [~1548 bytes per transaction](../cross-chain-communication/da.md#aztec-specific-data) + tree overhead, ~ 0.4 TB per year. +- **Storage**: [~1548 bytes per transaction](../data-publication-and-availability/index.md#aztec-specific-data) + tree overhead, ~ 0.4 TB per year. - **RAM**: Help -::: + ::: ### Sequencers @@ -65,9 +65,9 @@ An Aztec Prover is a full node that is producing Aztec-specific zero knowledge ( Mostly as full nodes. The compute and memory requirements might be larger since it needs to actually build the large proofs. Note, that the prover don't directly need to be a full node, merely have access to one. ::: -### Other types of network nodes +### Other types of network node -- [Validating Light nodes](../cross-chain-communication/index.md) +- [Validating Light nodes](../l1-smart-contracts/index.md) - Maintain a state root and process block headers (validate proofs), but do not store the full state. - The L1 bridge is a validating light node. - Can be used to validate correctness of information received from a data provider. @@ -113,7 +113,7 @@ Anyone ->> Network: eligible as a sequencer - In Diagram - add a dedicated timeline from the block production's PoV - get rid of "pre-confirmed" -::: + ::: ![Governance Summary Image](./images/Aztec-Block-Production-1.png) @@ -258,11 +258,11 @@ Future Aztec versions will receive rewards based on their staked amount, as dete With the rest of the protocol _mostly_ well defined, Aztec Labs now expects to begin a series of sprints dedicated towards economic analysis and modeling with [Blockscience](https://block.science/) throughout Q1-Q2 2024. This will result in a public report and associated changes to this documentation to reflect the latest thinking. ::: -## Mev-boost +## MEV-boost :::success -##### About MEV on Aztec +### About MEV on Aztec Within the Aztec Network, "MEV" (Maximal Extractable Value) can be considered "mitigated", compared to "public" blockchains where all transaction contents and their resulting state transitions are public. In Aztec's case, MEV is _generally_ only applicable to [public functions](#) and those transactions that touch publicly viewable state. ::: @@ -281,7 +281,7 @@ Initially it's expected that the negotiations and commitment could be facilitate ## Diagrams -#### Happy path +### Happy path :::danger TODO 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. @@ -318,7 +318,7 @@ Sequencers ->> Contract: exit() Sequencers --> Sequencers: wait 7 days ``` -#### Voting on upgrades +### 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. @@ -347,7 +347,7 @@ loop Happy Path Block Production end ``` -#### Backup mode +### 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. diff --git a/yellow-paper/docs/decentralization/governance.md b/yellow-paper/docs/decentralization/governance.md index 0a66ea4e472..249b3149edf 100644 --- a/yellow-paper/docs/decentralization/governance.md +++ b/yellow-paper/docs/decentralization/governance.md @@ -4,9 +4,9 @@ This is a first draft which articulates the latest thinking on governance & upgrades. It is subject to change and further review - ultimately needing team-wide understanding and approval. Please take this as a proposal, not as truth. ::: -### Summary +## Summary -We propose an immutable governance & upgrade mechanism for The Aztec Network ("Aztec") that is comprised of a version registry, which points to deployments ("instances", used interchangeably) of Aztec. +We propose an immutable governance & upgrade mechanism for The Aztec Network ("Aztec") that comprises a version registry, which points to deployments ("instances", used interchangeably) of Aztec. These instances may choose to be immutable themselves, or have governance that evolves over time alongside the community. The governance contract will keep track of governance votes, from the current version of Aztec, as well as direct token votes from the community, in order to provide some form of checks and balances. @@ -14,7 +14,7 @@ The version registry will keep track of all historical versions of Aztec & provi ![Governance Summary Image](./images/Aztec-Governance-Summary-1.png) -### Rewards +## Rewards We propose introducing a governance "version registry" which keeps track of a) which deployments of Aztec have been canonical, and b) which instances currently have tokens staked to them, specifically in order to issue a consistent, single new token in the form of _incentives_ or "rollup/block rewards". @@ -24,11 +24,16 @@ Given that deployments may be immutable, it is necessary to ensure that there ar Beyond making it easier to understand for users, having a single token across all deployments is necessary to ensure that all instances are all utilizing the same token due to ecosystem cohesive and business development efforts, for example, having reliable onramps and wallets. -### Initial deployment + + +## Initial deployment Upon initial deployment, there will be an immutable set of governance contracts which maintain the version registry, and an initial immutable instance of the rollup which will be the first "canonical" deployment. -The initial instance will be called "Aztec v0" and (the current thinking is that v0) will not include the ability to process user transactions. Sequencers can register for Fernet's sequencer selection algorithm by staking tokens to that particular instance, and practice proposing blocks on mainnet prior to deciding to "go live" with v1, which _does_ enable the processing of user transactions. This instance would then _"restake"_ these tokens within the governance contract, to have a voting weight equal to the amount of tokens staked by it's sequencer set. This is in order to ensure that the sequencer selection algorithm is working properly and the community of operators themselves can decide what happens to the network next, i.e., if it's ready to actually "go live" with transactions. It will also serve as a production readiness test of the upgradeability. In the event that these v0 tests are unable to be successfully completed as expected, the community (with potential foundation approval) may need to redeploy and try again. +The initial instance will be called "Aztec v0" and (the current thinking is that v0) will not include the ability to process user transactions. Sequencers can register for Fernet's sequencer selection algorithm by staking tokens to that particular instance, and practice proposing blocks on mainnet prior to deciding to "go live" with v1, which _does_ enable the processing of user transactions. This instance would then _"restake"_ these tokens within the governance contract, to have a voting weight equal to the amount of tokens staked by its sequencer set. This is in order to ensure that the sequencer selection algorithm is working properly and the community of operators themselves can decide what happens to the network next, i.e., if it's ready to actually "go live" with transactions. It will also serve as a production readiness test of the upgradeability. In the event that these v0 tests are unable to be successfully completed as expected, the community (with potential foundation approval) may need to redeploy and try again. ![Initial Deployment Image](./images/Aztec-Governance-Summary-3.png) @@ -36,26 +41,42 @@ The ability to upgrade to v1 is articulated below, and should follow a "happy pa ![Version 1 Deployment Image](./images/Aztec-Governance-Summary-4.png) -### Proposing a new version +## Proposing a new version + + The current canonical rollup ("current rollup") can at any point propose voting on a new instance to become canonical and added to the governance version registry contracts. It can have it's own logic for determining when it makes sense to do so, and trigger the formal governance vote. In the initial deployment it's expected to be done as articulated in the empire stakes back, where a sequencer must flag a desire to upgrade signal as part of Fernet's proposal phase, i.e., they won a random leader election, and a majority of sequencers must do so over a specific time horizon, e.g., 7 days. In addition to the current rollup implementation deciding to propose a vote, token holders can lock a sufficient amount of tokens for a sufficient amount of time in order to bypass the current rollup and propose a new version to become canonical next. This can be used in the scenario that the rollup implementation is so buggy it is unable to propose a new rollup to replace itself, or is due to potential community disagreement. In this scenario of disagreement, it is likely to be a very contentious action - as it implies a large token holder actively disagrees with the current rollup's sequencer set. + + - Current thinking is this would require locking 1% of _total supply_ for 2 years. - These tokens must be eligible for voting, as defined below. In a worst case scenario, the rollup's sequencer set could be malicious and censor potentially honest upgrade proposals from going through. In this scenario, there needs to be the ability to add a proposal "to the queue" via the token locking mechanism articulated above which is guaranteed to be executed when the previous vote completes. -#### Quorum +### Quorum For any proposal to be considered valid and ready for voting, there must be a quorum of voting power eligible to participate. The purpose of this is to ensure that the network cannot be upgraded without a minimum of participation, keeping the governance more protected from takeover at genesis. The exact amount of voting power required is to be determined through modelling, but we expect that around 5% of total supply. Assuming that 20% of the supply is circulating at launch and that 25% of this is staked towards the initial instance, this would allow the initial instance to reach quorum on its own. -### Voting +## Voting -#### Participation +### Participation Aztec's governance voting occurs within the governance contract, and the tokens being utilized must be "locked within governance" i.e., non-transferable. @@ -63,7 +84,7 @@ Any token holder is able to directly vote via an interaction with the governance The current canonical rollup can choose to implement its internal voting however it would like, with the weight of the tokens staked in that instance. This is likely to be a majority of voting weight, which we can reliably assume will vote each time. Generally this addresses the problems of low token holder participation! In the initial instance, we envision a version of the Empire Stakes back, where sequencers are voting during part of their block proposal phases. Not all sequencers will win a block proposal/election during the time period of the vote, this leads it to being a randomized sampling of the current sequencer set. -#### Exiting +### Exiting The duration of the token lock depends on the action a user participated in. Tokens that have been locked to vote "yes" to changing the canonical instance are locked within the governance contract until the "upgrade" has been performed _or_ when the voting period ends without the proposal gaining sufficient traction to reach quorum. @@ -71,7 +92,7 @@ Tokens whose power did not vote "yes" are free to leave whenever they chose. Thi Rollup instances themselves will need to deposit their stake into the governance, in order to earn rewards and participate within the vote. Further, they can apply their own enter/exit delays on top of the governance contract's. For example to ensure stability of the sequencer set over short timeframes, if using $AZTC stake as a requirement for sequencing, they may wish to impose longer entry and exit queues. -#### Results +### Results A vote is defined as passing if a majority of the voting weight votes "yes" to the proposal. @@ -83,17 +104,17 @@ If the vote passes, and a new rollup has been determined to be the next canonica Portals that blindly follow governance inherently assume that the new inbox/outbox will always be backwards compatible. If it is not, it might break the portals. ::: -### Timing +## Timing -#### Phase 1 - Setup +### Phase 1 - Setup After the current canonical rollup, or a sufficient number of tokens are locked in governance, there is a ~3-7 day preparation period where users get their tokens "ready" for voting. i.e., withdraw & deposit/lock for the vote, or choose a suitable delegate. -#### Phase 2 - Voting +### Phase 2 - Voting After setup has completed, there is a 7-30 day (TBD) period during which votes can land on the governance contract. In practice, we envision a majority of this voting happening in the current canonical instance and the voting weight of the current canonical instance being sufficient to reach quorum without any additional token delegation. -#### Phase 3 - Execution Delay (Timelock) +### Phase 3 - Execution Delay (Timelock) If a vote passes, there is a timelocked period before it becomes the new canonical rollup. This specific time period must be more than a minimum, e.g., 3 days, but is defined by the current rollup and in v1 may be controlled by both the sequencers in a happy path, and an emergency security council in a worst case scenario (articulated [below](#Emergency-mode)). In a typical happy path scenario, we suggest this is at least 30 days, and in an emergency, the shortest period possible. A maximum period may also be defined, e.g., 60 days to ensure that the network cannot be kept from upgrading by having a delay of 200 years. @@ -101,11 +122,11 @@ If a vote passes, there is a timelocked period before it becomes the new canonic It is worth acknowledging that this configurability on upgrade delay windows will likely be flagged on L2 beat as a "medium" centralization risk, due to the ability to quickly upgrade the software (e.g., a vacation attack). Explicitly this decision could cause us to be labeled a "stage 1" rather than "stage 2" rollup. However, if a vote is reasonably long, then it should be fine as you can argue that the "upgrade period" is the aggregate of all 3 periods. ::: -### Diagrams +## Diagrams -Importantly we differentiate between `Aztec Governance`, and the governance of a particular instance of Aztec. This diagram articulates the high level of Aztec Governance, specifically how the network can deploy new versions overtime which will be part of a cohesive ecosystem, sharing a single token. In this case, we are not concerned with how the current canonical rollup chooses to implement it's decision to propose a new version, nor how it implements voting. It can be reasonably assumed that this is a version of The Empire Stakes back, where a majority of the current rollup sequencers are agreeing to propose and want to upgrade. +Importantly we differentiate between `Aztec Governance`, and the governance of a particular instance of Aztec. This diagram articulates the high level of Aztec Governance, specifically how the network can deploy new versions over time which will be part of a cohesive ecosystem, sharing a single token. In this case, we are not concerned with how the current canonical rollup chooses to implement its decision to propose a new version, nor how it implements voting. It can be reasonably assumed that this is a version of The Empire Stakes back, where a majority of the current rollup sequencers are agreeing to propose and want to upgrade. -#### Happy path +### Happy path ```mermaid sequenceDiagram @@ -133,7 +154,7 @@ Next Rollup ->> Version Registry: markCanonical(nextRollup) Sequencers ->> Next Rollup: Proposing new blocks here! ``` -#### "Bricked" rollup proposals +### "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. @@ -199,27 +220,27 @@ Next Rollup ->> Version Registry: markCanonical(nextRollup) Sequencers ->> Next Rollup: Proposing new blocks here! ``` -### Emergency mode +## Emergency mode Emergency mode is proposed to be introduced to the initial instance "v0" or "v1" of Aztec, whatever the first instance or deployment is. Emergency mode **will not be included as part of the canonical governance contracts or registry**. If future deployments wish to have a similar security council, they can choose to do so. In this design, the current rollup can determine the timelock period as articulated above, within some predefined constraints, e.g., 3-30 days. Explicitly, the current rollup can give a security council the ability to define what this timelock period may be, and in the case of a potential vulnerability or otherwise, may be well within it's rights to choose the smallest value defined by the immutable governance contract to ensure that the network is able to recover and come back online as quickly as possible. ![Emergency Mode Image](./images/Aztec-Governance-Summary-4.png) -#### Unpausing by default +### Unpausing by default In the first instance, it's expected that this security council can _only_ pause the rollup instance, not make any other changes to the instance's functionality. It is important that after N days (e.g., 180), or after another rollup has been marked canonical and Y days (e.g., 60), this rollup _must_ become unpaused eventually - otherwise it's practically bricked from the perspective of those users choosing immutable portals, and could leave funds or other things belonging to users (e.g., identity credentials or something wacky) permanently inside of it. The same is true for all future instances that have pause functionalities. -#### Removing the emergency mode +### Removing the emergency mode The emergency mode articulated here may be implemented as part of the next instance of Aztec - "v1" or whatever it ends up being called, when mainnet blocks are enabled. The current sequencer set on v0 (the initial instance) would then need to vote as outlined above on marking this new deployment as the "canonical v1" or predecessor to the initial instance. This would then have all of the portal contracts follow v1, which may or may not have other [training wheels](https://discourse.aztec.network/t/aztec-upgrade-training-wheels/641). If the community wishes, they can always deploy a new instance of the rollup which removes the emergency mode and therefore the pause-only multisig. -### Contract implementation +## Contract implementation :::danger TO DO ::: -### Glossary +## Glossary :::danger TO DO diff --git a/yellow-paper/docs/decentralization/p2p-network.md b/yellow-paper/docs/decentralization/p2p-network.md index addea0c233e..791fb1346d7 100644 --- a/yellow-paper/docs/decentralization/p2p-network.md +++ b/yellow-paper/docs/decentralization/p2p-network.md @@ -1,8 +1,10 @@ # P2P Network + + ## Requirements for a P2P Network -When a rollup is successfully published, the state transitions it produces are published along with it, making them publicly available. This broadcasted state does not depend on the Aztec network for its persistence or distribution. Transient data however, such as pending user transactions for inclusion in future rollups, does rely on the network for this. It is important that the network provides a performant, permissionless and censorship resistant mechanism for the effective propagation of these transactions to all network participants. Without this, transactions may be disadvantaged and the throughput of the network will deteriorate. +When a rollup is successfully published, the state transitions it produces are published along with it, making them publicly available. This broadcasted state does not depend on the Aztec network for its persistence or distribution. Transient data however, such as pending user transactions for inclusion in future rollups, does rely on the network for availability. It is important that the network provides a performant, permissionless and censorship resistant mechanism for the effective propagation of these transactions to all network participants. Without this, transactions may be disadvantaged and the throughput of the network will deteriorate. Other data that may be transmitted over the network are the final rollup proofs to be submitted to the rollup contract, however the size and rate of these payloads should not make any meaningful impact on the bandwidth requirements. @@ -39,16 +41,16 @@ Aztec Node instances will offer a JSON RPC interface for consumption by a user's ### Network Bandwidth -Transactions are composed of several data elements and can vary in size. The transaction size is determined largely by the private kernel proof and whether the transaction deloys any public bytecode. A typical transaction that emits a private note and an unencrypted log, makes a public call and contains a valid proof would consume approximately 40Kb of data. A transaction that additionally deploys a contract would need to transmit the public bytecode on top of this. +Transactions are composed of several data elements and can vary in size. The transaction size is determined largely by the private kernel proof and whether the transaction deploys any public bytecode. A typical transaction that: emits a private note and an unencrypted log, makes a public call and contains a valid proof, would consume approximately 40Kb of data. A transaction that additionally deploys a contract would need to transmit the public bytecode on top of this. | Element | Size | | -------------------------------------------- | ----- | -| Public Inputs, Public Calls and Emitted Logs | ~8Kb | -| Private Kernel Proof | ~32Kb | +| Public Inputs, Public Calls and Emitted Logs | ~8KB | +| Private Kernel Proof | ~32KB | -If we take 2 values of transaction throughput of 10 and 100 transactions per second, we can arrive at average network bandwidth requirements of 400Kb and 4000Kb per second respectively. +If we take 2 values of transaction throughput of 10 and 100 transactions per second, we can arrive at average network bandwidth requirements of 400KB and 4000KB per second respectively. -### Sequencer to Prover Communication +### Sequencer-to-Prover Communication Proving is an out-of-protocol activity. The nature of the communication between sequencers and provers will depend entirely on the prover/s selected by the sequencer. Provers may choose to run their own Transaction Pool Node infrastructure so that they are prepared for generating proofs and don't need to receive this data out-of-band. diff --git a/yellow-paper/docs/gas-and-fees/gas-and-fees.md b/yellow-paper/docs/gas-and-fees/index.md similarity index 67% rename from yellow-paper/docs/gas-and-fees/gas-and-fees.md rename to yellow-paper/docs/gas-and-fees/index.md index 53e9c6f3dad..2ebf5d2e4e8 100644 --- a/yellow-paper/docs/gas-and-fees/gas-and-fees.md +++ b/yellow-paper/docs/gas-and-fees/index.md @@ -1,16 +1,32 @@ # Gas and Fees + + ## Requirements -Private state transition execution and proving is performed by the end user. However, once a transaction is submitted to the network, further resource is required to verify the private proofs, effect public state transitions and include the transaction within a rollup. This comes at the expense of the sequencer selected for the current slot. These resources include, but are not limited to: +Private state transition execution and proving is performed by the end user. However, once a transaction is submitted to the network, further resource is required to verify private kernel proofs, effect public state transitions and include the transaction within a rollup. This comes at the expense of the sequencer selected for the current slot. These resources include, but are not limited to: +1. Transaction [validation](../transactions/validity.md) 1. Execution of public function bytecode -2. Generation of initial witnesses and proving of public and rollup circuits -3. Storage of world state and computation of merkle proofs -4. Finalization of state transition functions on Ethereum -5. Storage of private notes +1. Generation of initial witnesses and proving of public and rollup circuits +1. Storage of world state and computation of merkle proofs +1. Finalization of state transition functions on Ethereum +1. Storage of private notes -Sequencers will need compensating for their efforts leading to requirements for the provision of payments to the sequencer. Note, some of the computation may be outsourced to third parties as part of the prover selection mechanism, the cost of this is borne by the sequencer outside of the protocol. +Sequencers will need compensating for their efforts, leading to requirements for the provision of payments to the sequencer. Note, some of the computation may be outsourced to third parties as part of the prover selection mechanism, the cost of this is borne by the sequencer outside of the protocol. We can define a number of requirements that serve to provide a transparent and fair mechanism of fee payments between transaction senders and sequencers. @@ -26,17 +42,19 @@ We can define a number of requirements that serve to provide a transparent and f ## High Level Concepts and Design 1. We will use concepts of L1, L2 and DA gas to universally define units of resource for the Ethereum and Aztec networks respectively. L1 gas directly mirrors the actual gas specification as defined by Ethereum, L2 gas covers all resource expended on the L2 network. Finally, DA gas accounts for the data stored on the network's Data Availability solution. -2. We will deterministically quantify all resource consumption of a transaction into 7 values. We will define these value later but essentially they represent the amortized and transaction specific quantities of each of L1, L2 and DA gas. +2. We will deterministically quantify all resource consumption of a transaction into 7 values. We will define these values later but essentially they represent the amortized and transaction-specific quantities of each of L1, L2 and DA gas. 3. The transaction sender will provide a single fee for the transaction. This will be split into 3 components to cover each of the L1, L2 and DA gas costs. The sender will specify `feePerGas` and `gasLimit` for each component. Doing so provides protection to the sender that the amount of fee applicable to any component is constrained. -4. We will constrain the sequencer to apply the correct amortized and transaction specific fees ensuring the sender can not be charged arbitrarily. +4. We will constrain the sequencer to apply the correct amortized and transaction-specific fees; ensuring the sender can not be charged arbitrarily. 5. We will define a method by which fees can be paid in any asset, either publicly or privately, on Ethereum or Aztec but where the sequencer retains agency as to what assets and fee payment methods they are willing to accept. 6. Upon accepting a transaction, we will constrain the sequencer to receive payment and provide any refund owing via the methods specified by the sender. ## Gas Metering -Broadly speaking, resource consumption incurred by the sequencer falls into categories of transaction specific consumption and amortized, per-rollup consumption. Each operation performed by the sequencer can be attributed with a fixed amount of gas per unit representing it's level of resource consumption. The unit will differ between operations, for example in some operations it may be per-byte whilst in others it could be per-opcode. What matters is that we are able to determine the total gas consumption of any given transaction. +Broadly speaking, resource consumption incurred by the sequencer falls into categories of transaction-specific consumption and amortized, per-rollup consumption. Each operation performed by the sequencer can be attributed with a fixed amount of gas per unit, representing its level of resource consumption. The unit will differ between operations, for example in some operations it may be per-byte whilst in others it could be per-opcode. What matters is that we are able to determine the total gas consumption of any given transaction. + +### Examples of Gas-Consuming Operations -### Examples of Gas Consuming Operations + Examples of operations for which we want to measure gas consumption are: @@ -53,32 +71,94 @@ Some operations are specific to a transaction, such as public function execution ### Measuring Gas Before Submission -All of the operations listed in the transaction specific table can provide us with deterministic gas values for a transaction. The transaction can be simulated and appropriate gas figures can be calculated before the transaction is sent to the network. The transaction will also need to provide a fee to cover it's portion of the amortized cost. This can be done by deciding on a value of `N`, the number of transactions in a rollup. Of course, the transaction sender can't know in advance how many other transactions will be included in the same rollup but the sender will be able to see how many transactions were included in prior rollups and decide on a value that will give them some certainty of inclusion without overpaying for insufficient amortization. As with all costs, any additional amortization will be refunded to the sender. +All of the operations listed in the transaction-specific table (below) can provide us with deterministic gas values for a transaction. The transaction can be simulated and appropriate gas figures can be calculated before the transaction is sent to the network. The transaction will also need to provide a fee to cover its portion of the amortized cost. This can be done by deciding on a value of `N`, the number of transactions in a rollup. Of course, the transaction sender can't know in advance how many other transactions will be included in the same rollup, but the sender will be able to see how many transactions were included in prior rollups and decide on a value that will give them some certainty of inclusion without overpaying for insufficient amortization. As with all costs, any additional amortization will be refunded to the sender. + +For example, if the previous 10 rollups each consist of an average of 5000 transactions, the sender could decide on a value of 5000 for `N` in its amortization. If the transaction is included in a rollup with > `N` transactions, the fee saved by the additional amortization will be refunded to the sender. If the sequencer chooses to include the transaction in a rollup with < `N` transactions, the sequencer will effectively subsidize that reduced amortization. -For example, if the previous 10 rollups consist of an average of 5000 transactions, the sender could decide on a value of 1000 for `N` in it's amortization. If the transaction is included in a rollup with > `N` transactions, the fee saved by the additional amortization will be refunded to the sender. If the sequencer chooses to include the transaction in a rollup with < `N` transactions, the sequencer will effectively subsidize that reduced amortization. + The transaction will be provided with 7 gas values: + + + + | Value | Description | | -------- | -------- | | `L1BaseGasLimit` | The maximum quantity of gas permitted for use in amortized L1 operations | -| `L1TxGasLimit` | The maximum quantity of gas permitted for use in transaction specific L1 operations | +| `L1TxGasLimit` | The maximum quantity of gas permitted for use in transaction-specific L1 operations | | `L2BaseGasLimit` | The maximum quantity of gas permitted for use in amortized L2 operations | -| `L2TxGasLimit` | The maximum quantity of gas permitted for use in transaction specific L2 operations | +| `L2TxGasLimit` | The maximum quantity of gas permitted for use in transaction-specific L2 operations | | `L2FeeDistributionGas` | The quantity of L2 gas the sequencer can charge for executing the fee distribution function | -| `DAFeeDistributionGas` | The quantity of DA gas the sequencer can charge for storing state updates produced as part of fee distribution | +| `DAFeeDistributionGas` | The quantity of DA gas the sequencer can charge for publishing state updates and events, which are produced as part of fee distribution | | `DATxGasLimit` | The maximum quantity of DA gas permitted for use in transaction specific Data Availability functions | + + By constraining each of the above values individually, the transaction sender is protected from a dishonest sequencer allocating an unfairly high amount of gas to one category and leaving insufficient gas for other categories causing a transaction to erroneously be deemed 'out of gas' and a fee taken for improper execution. ### Gas Measurement By A Sequencer -When a transaction is received by a sequencer, it will want to determine if the transaction has been endowed with sufficient fee to be considered for inclusion in a rollup. Although the transaction contains information as to the gas limits and fees it provides, these may not be accurate either because the sender is dishonest or because the simulation of any public functions was performed on a system state that differs to that at the point of inclusion. Unlike transactions on Ethereum, it is not simply a case of linearly executing the transactions opcodes until completion of the transaction exceeds the provided gas. Rollup inclusion and public function execution and proving require significant resource investment on the part of the sequencer even for the most trivial transaction. +When a transaction is received by a sequencer, they will want to determine if the transaction has been endowed with sufficient fee to be considered for inclusion in a rollup. Although the transaction contains information as to the gas limits and fees it provides, these may not be accurate: either because the sender is dishonest, or because the simulation of any public functions was performed on a system state that differed to that at the point of inclusion. Unlike transactions on Ethereum, it is not simply a case of linearly executing the transaction's opcodes until the provided gas limit is exceeded. Rollup inclusion, public function execution, and proving, all require significant resource investment on the part of the sequencer, even for the most trivial transaction. -There are a series of steps the sequencer would wish to perform such that it incrementally increases it's commitment to processing the transaction as it becomes more confident of a successful outcome: +There are a series of steps the sequencer would wish to perform such that it incrementally increases its commitment to processing the transaction as it becomes more confident of a successful outcome: -1. Determine how much fee has been provided and verify that this is sufficient to cover the L1, L2 and DA gas limits specified in the transaction. Later on we will look at how this is done but it may involve simulation of a public function. The sequencer will have visibility over which function on which contract has been specified for this step and has agency to disregard the transaction if it is not willing to execute this step. +1. Determine how much fee has been provided and verify that this is sufficient to cover the L1, L2 and DA gas limits specified in the transaction. Later on we will look at how this is done but it may involve simulation of a public function. The sequencer will have visibility over which public function on which contract has been specified for this step and has agency to disregard the transaction if it is not willing to execute this step. 2. Once the fee is known, verify that enough fee exists to cover the transaction's requirements at this stage. This would include publishing the results of the private stage of the transaction and the amortized cost of rollup construction and verification. 3. If at least one public function is enqueued, verify that enough fee exists to cover at least 1 iteration of the public VM, 1 iteration of the public kernel circuit and a non-zero amount left for public function simulation. The sequencer here will seek to determine if it is worth proceeding with the transaction. Proceeding requires an investment at least covering the cost of the minimum public VM execution and an iteration of the public kernel circuit. The minimum cost could be described as the cost to simulate, execute and prove a function which reverts as soon as it enters the function. @@ -136,7 +216,7 @@ We will attempt to walk through the process by which a transaction is created wi ### User Simulation and Fee Preparation -Transactions begin on a user's device where a user opts to interact privately with a contract. This execution results in the generation of new notes and nullifiers and potentially some enqueued public function calls. Additionally, at some point during this execution, a fee will need to be generated. The state updates related to this fee will be added to a separate collection of notes, nullifiers and public calls where these state updates only revert on failure of the fee preparation or distribution logic. +Transactions begin on a user's device, where a user opts to interact privately with a contract. This execution results in the generation of new notes, nullifiers, and events, and potentially some enqueued public function calls. Additionally, at some point during this execution, a fee will need to be generated. The state updates relating to the preparation and distribution of this fee will be added to a separate collection of notes, nullifiers, events, and public calls, and these state updates will only revert on failure of the fee preparation or fee distribution logic. This would appear to introduce a circular dependency whereby an appropriate fee can't be produced without knowing the gas profile (the required quantities of L1, L2 and DA gas), but the gas profile can depend on the fee required. When simulating the transaction, we will introduce values to the global context: diff --git a/yellow-paper/docs/intro.md b/yellow-paper/docs/intro.md index 9f872b58b81..04279ac270f 100644 --- a/yellow-paper/docs/intro.md +++ b/yellow-paper/docs/intro.md @@ -16,7 +16,7 @@ In particular, can we explain the protocol to the wider cryptography team, whose This document should be considered the foundation of the protocol. It shouldn't need to refer to the implementation details elsewhere in this monorepo. (The protocol should inform the implementation; not the other way around). -The details should be sufficient for some other engineering team to implement the entire protocol (save for a few exact details, which are details (here)(LINK)). +The details should be sufficient for some other engineering team to implement the entire protocol. Some of the info we need to populate this document might have already been written in the top-level `docs/` dir of the monorepo. But the target audience is different. Reduce verbose prose. Remove monorepo code snippets (but note that simple pseudocode snippets to explain a protocol concept are fine). Don't describe components of the sandbox (that's an implementation detail and doesn't belong in this doc). diff --git a/yellow-paper/docs/cross-chain-communication/images/com-abs-6.png b/yellow-paper/docs/l1-smart-contracts/images/com-abs-6.png similarity index 100% rename from yellow-paper/docs/cross-chain-communication/images/com-abs-6.png rename to yellow-paper/docs/l1-smart-contracts/images/com-abs-6.png diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-1.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-1.png new file mode 100644 index 00000000000..ebeebb2cee3 Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-1.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-2.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-2.png new file mode 100644 index 00000000000..ff8de6bcb48 Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-2.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-3.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-3.png new file mode 100644 index 00000000000..3710357206a Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-3.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-4.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-4.png new file mode 100644 index 00000000000..023ec03b4b8 Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-4.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-5.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-5.png new file mode 100644 index 00000000000..eddc2d12d9e Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-5.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-6.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-6.png new file mode 100644 index 00000000000..eac8af273fb Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-6.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image-7.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-7.png new file mode 100644 index 00000000000..1c1002bb65e Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image-7.png differ diff --git a/yellow-paper/docs/l1-smart-contracts/images/proposal/image.png b/yellow-paper/docs/l1-smart-contracts/images/proposal/image.png new file mode 100644 index 00000000000..f2c03432cd1 Binary files /dev/null and b/yellow-paper/docs/l1-smart-contracts/images/proposal/image.png differ diff --git a/yellow-paper/docs/cross-chain-communication/index.md b/yellow-paper/docs/l1-smart-contracts/index.md similarity index 98% rename from yellow-paper/docs/cross-chain-communication/index.md rename to yellow-paper/docs/l1-smart-contracts/index.md index 61e15a9cc0b..9767dfc07e2 100644 --- a/yellow-paper/docs/cross-chain-communication/index.md +++ b/yellow-paper/docs/l1-smart-contracts/index.md @@ -11,7 +11,7 @@ The purpose of the L1 contracts are simple: - Facilitate cross-chain communication such that L1 liquidity can be used on L2 - Act as a validating light node for L2 that every L1 node implicitly run -::: + ::: ## Overview @@ -141,7 +141,9 @@ For a generic DA that publishes data commitments to Ethereum, the oracle could b By having the availability oracle be independent from state progression we can even do multi-transaction blocks, e.g., use multiple transactions or commitments from other DA layers to construct the `TxsHash` for a large block. -For more information around the requirements we have for the availability oracle, see [Data Availability](./da.md). +For more information around the requirements we have for the availability oracle, see [Data Availability](../data-publication-and-availability/index.md). + + ### Registry @@ -214,6 +216,8 @@ We are using the `secretHash` to ensure that the user can spend the message priv When we say inbox, we are generally referring to the L1 contract that handles the L1 to L2 messages. + + The inbox is logically a [multi-set](https://en.wikipedia.org/wiki/Multiset) that builds messages based on the caller and user-provided content (multi-set meaning that repetitions are allowed). While anyone can insert messages into the inbox, only the recipient state transitioner can consume messages from it (as specified by the version). When the state transitioner is consuming a message, it MUST insert it into the "L2 outbox" ([message tree](./../state/index.md)). When a message is inserted into the inbox, the inbox **MUST** fill in the `sender`: @@ -236,7 +240,7 @@ The contract that sent the message must decide how to handle the cancellation. I While we have ensured that the message either arrives to the L2 outbox or is cancelled, we have not ensured that the message is consumed by the L2 contract. This is up to the L2 contract to handle. If the L2 contract does not handle the message, it will be stuck in the outbox forever. Similarly, it is up to the L1 contract to handle the cancellation. If the L1 contract does not handle the cancellation, the user might have a message that is pending forever. Error handling is entirely on the contract developer. ::: -##### L2 Inbox +#### L2 Inbox While the L2 inbox is not a real contract, it is a logical contract that apply mutations to the data similar to the L1 inbox to ensure that the sender cannot fake his position. This logic is handled by the kernel and rollup circuits. @@ -251,6 +255,11 @@ In practice, this is done in the kernel circuit of the L2, and the message hash The outboxes are the location where a user can consume messages from. An outbox can only contain elements that have previously been removed from the paired inbox. + + Our L1 outbox is pretty simple, Like the L1 inbox, it is a multi-set. It should allow the state transitioner to insert messages and the recipient of the message can consume it (removing it from the outbox). :::info Checking sender diff --git a/yellow-paper/docs/l1-smart-contracts/proposal.md b/yellow-paper/docs/l1-smart-contracts/proposal.md new file mode 100644 index 00000000000..6971fe2ebfc --- /dev/null +++ b/yellow-paper/docs/l1-smart-contracts/proposal.md @@ -0,0 +1,383 @@ +--- +title: Message Boxes Proposal +--- + +Proposal to update the message boxes for improved costs but with reduced usability. + + +## Background + +The current cross-chain communication mechanism was optimized for a few things: +- easy to consume messages from the L1 at a portal level +- giving the sequencer agency to decide what to include in the L2 + +This was achieved by having a `one-message-one-slot` design where each message is stored separately and the sequencer can decide which to include in the L2. +As part of a new block being inserted, it would need to "move" messages from one layer to the others. +This is done by updating the slot of the message. +For incoming messages (L1 -> L2) the moved messages are inserted into a merkle tree in the L2 state as part of the block proof. + +This design has two main drawbacks: +- you must bribe the sequencer to have your L1 -> L2 message included (adding another fee market) +- because messages need to update one slot per message, the number of messages constrains the block-size of the L2 + +## Introduction + +In this document, we propose 2 changes that can be applied independently. +Namely we propose a change to the inbox and a change to the outbox. + +The inbox change will primarily change how the sequencer builds his block, while the outbox change will change how the portal consumes messages. + +The changes have **no** impact on how the aztec contracts are written, but will alter the portal consumption on L1 with slightly increased complexity. + +### Ideas at a glimpse + +Instead of updating individual slots at the time we transition to a new state, we can build trees of messages ahead of time, and move just the roots of the trees (in L1 storage). + +This allows us to move a lot of messages at once without having to update a lot of storage — making it cheaper to move messages independent on the number of messages. + +For the incoming messages, this means that we can get rid of the fee market that was induced by the need for the sequencer to choose the messages to include messages in the L2. +And instead force it to move a root of a message tree. + +For outgoing, this means that we only have to insert one root into the L1 storage, and that the consumer will need to provide an inclusion proof (or have prepared the inclusion already). + +## The Inbox + +The inbox changes requires a larger remodelling of the current design. +Namely, it needs to update the L1 contract to build a merkle root of messages to be included, and the circuits need to be altered to correctly insert messages from this update. + +### The L1 Contract + +The L1 contract (Inbox) needs to build trees of incoming messages. +We say "trees" since we will be building a tree for each block, instead of one large collective tree. + +The reasoning is fairly straight-forward; we need to split it into epochs such that a sequencer can build a proof based on a tree that is not going to update in the middle of the proof building. +Such updates would allow DOS attacks on the sequencer, which is undesirable. + +To support this, we can simply introduce a "lag" between when trees are built and when they must be included. +We can actually do this quite easily. +Say that whenever a new block is published, we start building a new tree. +Essentially meaning that at block $n$ we include tree $n$ which was created earlier (during block $n-1$). + +Example visualized below. +Here we have that tree $n$ is "fixed" when block $n$ needs to be published. +And that tree $n+1$ is being built upon until block $n$ is being published. + +![Feeding trees into the blocks](images/proposal/image.png) + +Since we will be building the tree on L1, we need to use a gas-friendly hash-function such as SHA256. +However, as we need to allow users to prove inclusion in this tree, we cannot just insert the SHA256 tree into the rollup state, it requires too many constraints to be used by most small users. +Therefore, we need to "convert" the tree into a tree using a more snark-friendly hash. + +Furthermore, to build the tree on L1, we need to put some storage on L1 such that the insertions don't need to provide a lot of merkle-related data which could be cumbersome to do and prone to race-conditions. +For example two insertions based on inclusion paths that are created at the same time will invalidate each other. +As storage costs an arm and a leg on L1, we need to be careful with how we store this. + +Luckily for us, we can use a "frontier" merkle tree to store the messages. +This is a special kind of append-only merkle tree that allows us to store very few elements in storage, but just enough for us to be able to extend it, and compute the root of the tree. +Consult [Frontier Merkle Tree](#frontier-merkle-tree]) for more information on this. + +Assuming that we have these trees, we can build an `inbox` utilizing them as follows. +When a new block is published, we start building a new tree. +Notice however, that if we have entirely filled the current tree, we can start building a new one immediately, and the blocks can then "catch up". + + +```python +class Inbox: + STATE_TRANSITIONER: immutable(address) + ZERO: immutable(bytes32) + + HEIGHT: immutable(uint256) + SIZE: immutable(uint256) + + trees: HashMap[uint256, FrontierTree] + + to_include: uint256 = 0 + in_progress: uint256 = 1 + + def __init__(self, _height: uint256, _zero: bytes32, _state_transitioner: address): + self.HEIGHT = _height + self.SIZE = 2**_height + self.ZERO = _zero + self.STATE_TRANSITIONER = _state_transitioner + + self.trees[1] = FrontierTree(self.HEIGHT) + + def insert(self, message: L1ToL2Message) -> bytes32: + ''' + Insert into the next FrontierTree. If the tree is full, creates a new one + ''' + if self.trees[self.in_progress].next_index == 2**self.HEIGHT: + self.in_progress += 1 + self.trees[self.in_progress] = FrontierTree(self.HEIGHT) + + message.sender.actor = msg.sender + message.sender.chain_id = block.chainid + + leaf = message.hash_to_field() + self.trees[self.in_progress].insert(leaf) + return leaf + + def consume(self) -> bytes32: + ''' + Consumes the current tree, and starts a new one if needed + ''' + assert msg.sender == self.STATE_TRANSITIONER + + root = self.ZERO + if self.to_include > 0: + root = self.trees[self.to_include].root() + + # If we are "catching up" we can skip the creation as it is already there + if self.to_include + 1 == self.in_progress: + self.in_progress += 1 + self.trees[self.in_progress] = FrontierTree(self.HEIGHT) + + self.to_include += 1 + + return root +``` + + +Briefly our idea is as follows: +1. Build a SHA256 merkle tree of the messages on L1 for every block +2. Store the root of the tree in the L1 contract +3. Generate a new block which includes the "pending" messages into the L2 state +4. Publish this block, which loads in the pending root and starts the next epoch. +5. Repeat + + + +### Circuits +The exact mechanism of inserting the messages into the L2 state is not fully decided, but it will essentially be one of the following: +- Split the work across the existing base-rollup circuits +- Create a new circuit that only handles the insertion of the messages + +Both solutions will compute and update the snark-friendly L1 to L2 message tree that is part of the [rollup state](./../state/index.md). + +#### Divide and Conquer + +Divide the tree into smaller sub-trees, and have every base-rollup circuit convert a sub-tree into a snark-friendly sub-tree. +Then at every merge we merge two sub-trees into a larger sub-tree, exactly as most other trees in the rollup circuits. + +The main issue of this solution is that it doesn't fit nicely with small blocks. +For example, as the tree size will likely be fixed, you will have to construct at minimum enough base rollups to include those. +For smaller blocks this means that the overhead of the message tree could be quite large, and larger than doing it separately. + +However, a benefit is that we don't need a separate circuit type that feeds into the current ones, so the structure is kept simple. + +#### New Circuit + +The idea is simple. Create a new circuit (or circuits) that deals with converting the message tree into a snark-friendly tree. +The cost of producing a block (compute wise) will be more stable in this case, but we need to coordinate it separately and it will require additional circuits to be combined with the current ones. + + +## The Outbox + +The outbox change is actually pretty straight forward. As part of our block proof we are already constructing an `out_hash` as defined in [Rollup Circuits](./../rollup-circuits/index.md#state-availability). + +This hash is a merkle root of all the messages that are to be added to the outbox and we can simply insert it and its height into the outbox when processing a block. +We use the height to ensure that the merkle inclusion proofs are of the correct length. + +Whenever a portal wishes to consume a message, it must prove that it is included in one of these roots and that it has not been consumed before. +This is a very similar structure to what we are doing within the rollup for UTXO's already, so it should be familiar. + +To address the nullifier (marking it is spent), we can simply use a bitmap and flip just 1 bit per message. +This shares some of the cost of consuming. + +This structure is the same as is used in many merkle airdrop contracts, and is a well known pattern. +Nevertheless, it require a bit more work from the developers side, as they need to prepare the inclusion proof before they can consume the message. +The proof can be prepared based on the published data, so with good libraries it should be very straight forward for most cases. + +```python +class Outbox: + STATE_TRANSITIONER: immutable(address) + + struct RootData: + root: bytes32 + height: uint256 + nullified: HashMap[uint256, bool] + + roots: HashMap[uint256, RootData] + + def __init__(self, _state_transitioner: address): + self.STATE_TRANSITIONER = _state_transitioner + + def insert(index: uint256, root: bytes32, height: uint256): + assert msg.sender == self.STATE_TRANSITIONER + self.roots[index] = RootData(root, height, {}) + + def consume( + root_index: uint256, + leaf_index: uint256, + message: L2ToL1Message, + inclusion_proof: bytes[] + ): + leaf = message.hash_to_field() + assert merkle_verify( + self.roots[root_index].root, + self.roots[root_index].height, + leaf, + inclusion_proof + ) + assert not(self.roots[root_index].nullified[leaf_index]) + self.roots[root_index].nullified[leaf_index] = True +``` + +--- + +## Frontier Merkle Tree + +The Frontier Merkle Tree is an append only Merkle tree that is optimized for minimal storage on chain. +By storing only the right-most non-empty node at each level of the tree we can always extend the tree with a new leaf or compute the root without needing to store the entire tree. +We call these values the frontier of the tree. +If we have the next index to insert at and the current frontier, we have everything we need to extend the tree or compute the root, with much less storage than a full merkle tree. + +We will go through a few diagrams and explanations to understand how this works. +And then a pseudo implementation is provided. + + +### Insertion +Whenever we are inserting, we need to update the "root" of the largest subtree possible. +This is done by updating the node at the level of the tree, where we have just inserted its right-most descendant. +This can sound a bit confusing, so we will go through a few examples. + +At first, say that we have the following tree, and that it is currently entirely empty. + +![alt text](images/proposal/image-1.png) + +#### The first leaf + +When we are inserting the first leaf (lets call it A), the largest subtree is that leaf value itself (level 0). +In this case, we simply need to store the leaf value in `frontier[0]` and then we are done. +For the sake of visualization, we will be drawing the elements in the `frontier` in blue. + +![alt text](images/proposal/image-2.png) + +Notice that this will be the case whenever we are inserting a leaf at an even index. + +#### The second leaf + +When we are inserting the second leaf (lets call it B), the largest subtree will not longer be at level 0. +Instead it will be level 1, since the entire tree below it is now filled! +Therefore, we will compute the root of this subtree, `H(frontier[0],B)` and store it in `frontier[1]`. + +Notice, that we don't need to store the leaf B itself, since we won't be needing it for any future computations. +This is what makes the frontier tree efficient - we get away with storing very little data. + +![alt text](images/proposal/image-3.png) + +#### Third leaf +When inserting the third leaf, we are again back to the largest subtree being filled by the insertion being itself at level 0. +The update will look similar to the first, where we only update `frontier[0]` with the new leaf. + +![alt text](images/proposal/image-4.png) + +#### Fourth leaf + +When inserting the fourth leaf, things get a bit more interesting. +Now the largest subtree getting filled by the insertion is at level 2. + +To compute the new subtree root, we have to compute `F = H(frontier[0], E)` and then `G = H(frontier[1], F)`. +G is then stored in `frontier[2]`. + + +As before, notice that we are only updating one value in the frontier. +![alt text](images/proposal/image-5.png) + +### Figuring out what to update + +To figure out which level to update in the frontier, we simply need to figure out what the height is of the largest subtree that is filled by the insertion. +While this might sound complex, it is actually quite simple. +Consider the following extension of the diagram. +We have added the level to update, along with the index of the leaf in binary. +Seeing any pattern? + +![alt text](images/proposal/image-6.png) + +The level to update is simply the number of trailing ones in the binary representation of the index. +For a binary tree, we have that every `1` in the binary index represents a "right turn" down the tree. +Walking up the tree from the leaf, we can simply count the number of right turns until we hit a left-turn. + +### How to compute the root + +Computing the root based on the frontier is also quite simple. +We can use the last index inserted a leaf at to figure out how high up the frontier we should start. +Then we know that anything that is at the right of the frontier has not yet been inserted, so all of these values are simply "zeros" values. +Zeros here are understood as the root for a subtree only containing zeros. + +For example, if we take the tree from above and compute the root for it, we would see that level 2 was updated last. +Meaning that we can simply compute the root as `H(frontier[2], zeros[2])`. + +![alt text](images/proposal/image-7.png) + +For cases where we have built further, we simply "walk" up the tree and use either the frontier value or the zero value for the level. + +### Pseudo implementation +```python +class FrontierTree: + HEIGHT: immutable(uint256) + SIZE: immutable(uint256) + + frontier: HashMap[uint256, bytes32] # level => node + zeros: HashMap[uint256, uint256] # level => root of empty subtree of height level + + next_index: uint256 = 0 + + # Can entirely be removed with optimizations + def __init__(self, _height_: uint256): + self.HEIGHT = _height + self.SIZE = 2**_height + # Populate zeros + + def compute_level(_index: uint256) -> uint256: + ''' + We can get the right of the most filled subtree by + counting the number of trailing ones in the index + ''' + count = 0 + x = _index + while (x & 1 == 1): + count += 1 + x >>= 1 + return count + + def root() -> bytes32: + ''' + Compute the root of the tree + ''' + if self.next_index == 0: + return self.zeros[self.HEIGHT] + elif self.next_index == SIZE: + return self.frontier[self.HEIGHT] + else: + index = self.next_index - 1 + level = self.compute_level(index) + + temp: bytes32 = self.frontier[level] + + bits = index >> level + for i in range(level, self.HEIGHT): + is_right = bits & 1 == 1 + if is_right: + temp = sha256(frontier[i], temp) + else: + temp = sha256(temp, self.zeros[i]) + bits >>= 1 + return temp + + def insert(self, _leaf: bytes32): + ''' + Insert a leaf into the tree + ''' + level = self.compute_level(next_index) + right = _leaf + for i in range(0, level): + right = sha256(frontier[i], right) + self.frontier[level] = right + self.next_index += 1 +``` + +### Optimizations +- The `zeros` can be pre-computed and stored in the `Inbox` directly, this way they can be shared across all of the trees. + + diff --git a/yellow-paper/docs/logs/index.md b/yellow-paper/docs/logs/index.md index eeeaa07b9b5..343b4d980fe 100644 --- a/yellow-paper/docs/logs/index.md +++ b/yellow-paper/docs/logs/index.md @@ -2,14 +2,15 @@ title: Logs --- -Logs on Aztec are similar to logs on Ethereum, serving the purpose of enabling smart contracts to convey arbitrary data to external entities. This communication occurs through three distinct types of logs: + + + +Logs on Aztec are similar to logs on Ethereum, enabling smart contracts to convey arbitrary data to external entities. Offchain applications can use logs to interpret events that have occurred on-chain. There are three types of log: - [Unencrypted log](#unencrypted-log). - [Encrypted log](#encrypted-log). - [Encrypted note preimage](#encrypted-note-preimage). -These logs are generated in the course of contract function executions and play a pivotal role in aiding users to comprehend and leverage the received block data while facilitating interaction with the network. - ## Requirements 1. **Availability**: The logs get published. @@ -18,11 +19,11 @@ These logs are generated in the course of contract function executions and play 2. **Immutability**: A log cannot be modified once emitted. - The protocol ensures that once a proof is generated at any stage (for a function, transaction, or block), the emitted logs are finalized. In other words, only the original log preimages can generate the committed hashes in the proof. Any party can use this attribute to verify that the provided log preimages are not tempered. + The protocol ensures that once a proof is generated at any stage (for a function, transaction, or block), the emitted logs are tamper-proof. In other words, only the original log preimages can generate the committed hashes in the proof. 3. **Integrity**: A contract cannot impersonate another contract. - Every log is emitted by a specific contract, necessitating the identification of the contract address. This information is crucial for subsequent interactions with the contract or for interpreting the received data. The protocol ensures that the source contract's address for a log can be verified, while also preventing the forging of the addresses. + Every log is emitted by a specific contract, and users need assurances that a particular log was indeed generated by a particular contract (and not some malicious impersonator contract). The protocol ensures that the source contract's address for a log can be verified, while also preventing the forging of the address. ## Log Hash @@ -30,22 +31,28 @@ These logs are generated in the course of contract function executions and play The protocol uses **SHA256** as the hash function for logs, and then reduces the 256-bit result to 253 bits for representation as a field element. + + Throughout this page, `hash(value)` is an abbreviated form of: `truncate_to_field(SHA256(value))` ### Hashing -Regardless of the log type, the hash is derived from an array of fields, calculated as: +Regardless of the log type, the log hash is derived from an array of fields, calculated as: `hash(log_preimage[0], log_preimage[1], ..., log_preimage[N - 1])` -Here, _log_preimage_ is an array of field elements of length _N_, representing the data to be broadcasted. +Here, _log_preimage_ is an array of field elements of length `N`, representing the data to be broadcast. #### Emitting Logs from Function Circuits -A function can emit an arbitrary number of logs, provided they don't exceed the specified [limit]. The function circuits must compute a hash for each log, and push all the hashes into the public inputs for further processing by the protocol circuits. + + +A function can emit an arbitrary number of logs, provided they don't exceed the specified [limit] . The function circuits must compute a hash for each log, and push all the hashes into the public inputs for further processing by the protocol circuits. #### Aggregation in Protocol Circuits + + To minimize the on-chain verification data size, protocol circuits aggregate log hashes. The end result is a single hash within the root rollup proof, encompassing all logs of the same type. Each protocol circuit outputs two values for each log type: @@ -63,7 +70,7 @@ For private and public kernel circuits, beyond aggregating logs from a function ### Encoding -1. The encoded logs data of a transaction is a flatten array of all logs data within the transaction: +1. The encoded logs data of a transaction is a flattened array of all logs data within the transaction: _`tx_logs_data = [number_of_logs, ...log_data_0, ...log_data_1, ...]`_ @@ -76,7 +83,7 @@ For private and public kernel circuits, beyond aggregating logs from a function - _number_of_transactions_ is the number of leaves in the left-most branch, restricted to either _1_ or _2_. - _number_of_branches_ is the depth of the parent node of the left-most leaf. -Here is a step-by-step example to construct the _block_logs_data_: +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_: diff --git a/yellow-paper/docs/private-message-delivery/encryption-and-decryption.md b/yellow-paper/docs/private-message-delivery/encryption-and-decryption.md index e42072de18d..a00e82bea19 100644 --- a/yellow-paper/docs/private-message-delivery/encryption-and-decryption.md +++ b/yellow-paper/docs/private-message-delivery/encryption-and-decryption.md @@ -1,6 +1,6 @@ # Encryption and Decryption -Applications should be able to provably encrypt data for a target user, as part of private message delivery. As stated on the Keys section, we define three types of encrypted data, based on the sender and the recipient, from the perspective of a user: +Applications should be able to provably encrypt data for a target user, as part of private message delivery. As stated in the Keys section, we define three types of encrypted data, based on the sender and the recipient, from the perspective of a user: - Incoming data: data created by someone else, encrypted for and sent to the user. - Outgoing data: data created by the user to be sent to someone else, encrypted for the user. diff --git a/yellow-paper/docs/private-message-delivery/index.md b/yellow-paper/docs/private-message-delivery/index.md index 679d3e9abb5..c15f4cb06cf 100644 --- a/yellow-paper/docs/private-message-delivery/index.md +++ b/yellow-paper/docs/private-message-delivery/index.md @@ -2,6 +2,12 @@ title: Private Message Delivery --- + + # Private Message Delivery Private message delivery encompasses the encryption, tagging, and broadcasting of private messages on the Aztec Network. diff --git a/yellow-paper/docs/private-message-delivery/note-discovery.md b/yellow-paper/docs/private-message-delivery/note-discovery.md index ac5776b0949..8f4bee16e39 100644 --- a/yellow-paper/docs/private-message-delivery/note-discovery.md +++ b/yellow-paper/docs/private-message-delivery/note-discovery.md @@ -1,3 +1,5 @@ + + # Note Discovery When users interact with contracts they will generate and publish encrypted notes for other network participants. In order for a user to consume notes that belong to them, they need to identify, retrieve and decrypt them. A simple, privacy-preserving approach to this would be to download all of the notes and attempt decryption. However, the total number of encrypted notes published by the network will be substantial, making it infeasible for some users to do this. Those users will want to utilize a note discovery protocol to privately identify their notes. diff --git a/yellow-paper/docs/private-message-delivery/private-msg-delivery.md b/yellow-paper/docs/private-message-delivery/private-msg-delivery.md index e82ab0f34c3..04ba5fcdd0e 100644 --- a/yellow-paper/docs/private-message-delivery/private-msg-delivery.md +++ b/yellow-paper/docs/private-message-delivery/private-msg-delivery.md @@ -1,32 +1,36 @@ # Private Message Delivery -Maintaining the core tenet of privacy within the Aztec Network imposes a number of requirements related to the transfer of notes from one user to another. If Alice executes a function that generates a note for Bob: +In Aztec, users need to pass private information between each other. Whilst Aztec enables users to share arbitrary private messages, we'll often frame the discussion towards a sender sharing the preimage of a private note with some recipient. + +If Alice executes a function that generates a note for Bob: 1. Alice will need to **encrypt** that note such that Bob, and only Bob is able to decrypt it. -2. Alice will need to **broadcast** the encrypted note so as to make it available for Bob to retrieve. -3. Alice will need to **broadcast a 'tag'** alongside the encrypted note. This tag must be identifiable by Bob's chosen [note discovery protocol](./note-discovery.md) but not identifiable by any third party. +2. Alice will need to **broadcast** the encrypted note ciphertext so as to make it available for Bob to retrieve. +3. Alice will need to **broadcast a 'tag'** alongside the encrypted note ciphertext. This tag must be identifiable by Bob's chosen [note discovery protocol](./note-discovery.md) but not identifiable by any third party as "intended for Bob". ## Requirements - **Users must be able to choose their note tagging mechanism**. We expect improved note discovery schemes to be designed over time. The protocol should be flexible enough to accommodate them and for users to opt in to using them as they become available. This flexibility should be extensible to encryption mechanisms as well as a soft requirement. - **Users must be able to receive notes before interacting with the network**. A user should be able to receive a note just by generating an address. It should not be necessary for them to deploy their account contract in order to receive a note. -- **Applications must be able to safely send notes to any address**. Sending a note to an account could potentially transfer control of the call to that account, allowing the account to control whether they want to accept the note or not, and potentially bricking an application, since there is no catching exceptions in private function execution. +- **Applications must be able to safely send notes to any address**. Sending a note to an account could potentially transfer control of the call to that account, allowing the account to control whether they want to accept the note or not, and potentially bricking an application, since there are no catching exceptions in private function execution. - **Addresses must be as small as possible**. Addresses will be stored and broadcasted constantly in applications. Larger addresses means more data usage, which is the main driver for cost. Addresses must fit in at most 256 bits, or ideally a single field element. - **Total number of function calls should be minimized**. Every function call requires an additional iteration of the private kernel circuit, which adds several seconds of proving time. - **Encryption keys should be rotatable**. Users should be able to rotate their encryption keys in the event their private keys are compromised, so that any further interactions with apps can be private again, without having to migrate to a new account. ## Constraining Message Delivery -The protocol will allow constraining: +The protocol will enable app developers to constrain the correctness of the following: 1. The encryption of a user's note. 2. The generation of the tag for that note. -3. The publication of that note to the correct data availability layer. +3. The publication of that note and tag to the correct data availability layer. -Each app will define whether to constrain each step in private message delivery. Encryption and tagging will be done through a set of precompiled contracts, each contract offering a different mechanism, and users will advertise their preferred mechanisms in a canonical registry. +Each app will define whether to constrain each such step. Encryption and tagging will be done through a set of [precompiled contracts](../addresses-and-keys/precompiles.md), each contract offering a different mechanism, and users will advertise their preferred mechanisms in a canonical [registry](./registry.md). The advantages of this approach are: + + 1. It enables a user to select their preferred [note discovery protocol](./note-discovery.md) and [encryption scheme](./encryption-and-decryption.md). 2. It ensures that notes are correctly encrypted with a user's public encryption key. 3. It ensures that notes are correctly tagged for a user's chosen [note discovery protocol](./note-discovery.md). diff --git a/yellow-paper/docs/private-message-delivery/registry.md b/yellow-paper/docs/private-message-delivery/registry.md index d23a717df3c..d2302aa5c83 100644 --- a/yellow-paper/docs/private-message-delivery/registry.md +++ b/yellow-paper/docs/private-message-delivery/registry.md @@ -1,22 +1,34 @@ # Registry -The protocol should allow users to express their preferences in terms of encryption and note tagging mechanisms, and also provably advertise their encryption public keys. A canonical registry contract provides an application-level solution to both problems. + + +The protocol should allow users to express their preferences in terms of encryption & tagging mechanisms, and also provably advertise their encryption & tagging public keys. A canonical registry contract provides an application-level solution to both problems. ## Overview and Usage -At the application level, a canonical singleton contract allows accounts register their public keys and their preference for encryption and tagging methods. This data is kept in public storage for anyone to check when they need to send a note to an account. +At the application level, a canonical singleton contract allows accounts to register their public keys and their preference for encryption & tagging methods. This data is kept in public storage for anyone to check when they need to send a note to an account. -An account can directly call the registry via a public function to set or update their public keys and encryption method. New accounts should register themselves on deployment. Alternatively, anyone can create an entry for a new account (but not update) if they show the public key and encryption method can be hashed to the address. This allows third party services to register addresses to improve usability. +An account can directly call the registry via a public function to set or update their public keys and their encryption & tagging preferences. New accounts should register themselves on deployment. Alternatively, anyone can create an entry for a new account (but not update) if they demonstrate that the public key and encryption & tagging method can be hashed to the new account's address. This allows third party services to register addresses to improve usability. -An app contract can provably read the registry during private execution via a merkle membership proof against the latest public state root. Rationale for not making a call to the registry to read is to reduce the number of function calls. When reading public state from private-land, apps must set a max-block-number for the current transaction to ensure the public state root is not more than N blocks old. This means that, if a user rotates their public key, for at most N blocks afterwards they may still receive notes encrypted using their old public key, which we consider to be acceptable. +An app contract can provably read the registry during private execution via a merkle membership proof against a recent public state root, using the [archive tree](../state/archive.md). The rationale for not making a call to the registry to read is to reduce the number of function calls. When reading public state from private-land, apps must set a `max_block_number` for the current transaction to ensure the public state root is not more than `N = max_block_number - current_block_number` blocks old. This means that, if a user rotates their public key, for at most `N` blocks afterwards they may still receive notes encrypted using their old public key, which we consider to be acceptable. An app contract can also prove that an address is not registered in the registry via a non-inclusion proof, since the public state tree is implemented as an indexed merkle tree. To prevent an app from proving that an address is not registered when in fact it was registered less than N blocks ago, we implement this check as a public function. This means that the transaction may leak that an undisclosed application attempted to interact with a non-registered address but failed. -Note that, if an account is not registered in the registry, a sender could choose to supply the public key along with the preimage of an address on-the-fly, if this preimage was shared with them off-chain. This allows a user to send notes to a recipient before the recipient has deployed their account contract. +Note that, if an account is not registered in the registry, a sender could choose to supply the public key along with the preimage of an address on-the-fly , if this preimage was shared with them off-chain. This allows a user to send notes to a recipient before the recipient has deployed their account contract. ## Pseudocode -The registry contract exposes functions for setting public keys and encryption methods, plus a public function for proving non-membership. Reads are meant to be done directly via storage proofs and not via calls to save on proving times. Encryption and tagging preferences are expressed via their associated precompile address. +The registry contract exposes functions for setting public keys and encryption methods, plus a public function for proving non-membership of some address. Reads are meant to be done directly via storage proofs and not via calls to save on proving times. Encryption and tagging preferences are expressed via their associated precompile address. + + + + + + + + ``` contract Registry @@ -29,6 +41,7 @@ contract Registry public fn set_from_preimage(address, keys, precompile_address, ...address_preimage) assert address not in registry assert hash(keys, precompile_address, ...address_preimage) == address + // Q: Shouldn't this be `this.do_set(address, keys, precompile_address)`? this.set(msg_sender, keys, precompile_address) public fn assert_non_membership(address) @@ -38,6 +51,7 @@ contract Registry assert precompile_address in ENCRYPTION_PRECOMPILE_ADDRESS_RANGE assert precompile_address.validate_keys(keys) assert keys.length < MAX_KEYS_LENGTH + // Q: Shouldn't this be `registry[address] = ... ?` registry[msg_sender] = { keys, precompile_address } ``` @@ -45,7 +59,7 @@ contract Registry The registry stores a struct for each user, which means that each entry requires multiple storage slots. Reading multiple storage slots requires multiple merkle membership proofs, which increase the total proving cost of any execution that needs access to the registry. -To reduce the number of merkle membership proofs, the registry keeps in storage only the hash of the data stored, and emits the preimage as an unencrypted event. Nodes are expected to store these preimages, so they can be returned when clients query for the public keys for an address. Clients then prove that the preimage hashes to the commitment stored in the public data tree via a single merkle membership proof. +To reduce the number of merkle membership proofs, the registry keeps in storage only the hash of the data stored, and emits the preimage as an unencrypted event. Nodes are expected to store these preimages, so they can be returned when clients query for the public keys for an address. Clients then prove that the preimage hashes to the commitment stored in the public data tree via a single merkle membership proof. Note that this optimization may also be included natively into the protocol, [pending this discussion](https://forum.aztec.network/t/storing-data-of-arbitrary-length-in-the-public-data-tree/2669). @@ -70,6 +84,8 @@ contract Sample ``` + + ## Discussion diff --git a/yellow-paper/docs/private-message-delivery/send-note-guidelines.md b/yellow-paper/docs/private-message-delivery/send-note-guidelines.md index 73355e0acbf..b3394085a37 100644 --- a/yellow-paper/docs/private-message-delivery/send-note-guidelines.md +++ b/yellow-paper/docs/private-message-delivery/send-note-guidelines.md @@ -6,7 +6,7 @@ In order to satisfy the requirements established for private message delivery, w ## Provably Sending a Note -To provably encrypt, tag, and send a note to a recipient, applications should first check the registry. This ensures that the latest preferences for the recipient are honored, in case they rotated their keys. The registry should be queried via a direct storage read and not a function call, in order to save an additional recursion which incurs in extra proving time. +To provably encrypt, tag, and send a note to a recipient, applications should first check the registry. This ensures that the latest preferences for the recipient are honored, in case they rotated their keys or updated their precompile preference. The registry should be queried via a direct storage read and not a function call, in order to save an additional recursion which incurs in extra proving time. If the recipient is not in the registry, then the app should allow the sender to provide the recipient's public key from the recipient's address preimage. This allows users who have never interacted with the chain to receive encrypted notes, though it requires a collaborative sender. @@ -16,7 +16,7 @@ Execution of the precompile that implements the recipient's choice for encryptio ## Pseudocode -The following pseudocode covers how to provably send a note to a recipient, given an `encryption_type` (incoming, outgoing, or internal incoming). Should the registry support [multiple entries for a given recipient](./registry.md#multiple-recipients-per-address), this method must execute a batched call per each entry recovered from the registry. +The following pseudocode covers how to provably send a note to a recipient, given an `encryption_type` (incoming, outgoing, or internal incoming). Should the registry support [multiple entries for a given recipient](./registry.md#multiple-recipients-per-address), this method must execute a batched call per each entry recovered from the registry. ``` fn provably_send_note(recipient, note, encryption_type) diff --git a/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx b/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx index 4a28d65d2da..d11198262d2 100644 --- a/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx +++ b/yellow-paper/docs/public-vm/gen/_InstructionSet.mdx @@ -470,7 +470,7 @@ Addition (a + b) - **Opcode**: 0x00 - **Category**: Compute - Arithmetic - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input @@ -491,7 +491,7 @@ Subtraction (a - b) - **Opcode**: 0x01 - **Category**: Compute - Arithmetic - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input @@ -512,7 +512,7 @@ Multiplication (a * b) - **Opcode**: 0x02 - **Category**: Compute - Arithmetic - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input @@ -533,7 +533,7 @@ Unsigned division (a / b) - **Opcode**: 0x03 - **Category**: Compute - Arithmetic - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input @@ -554,7 +554,7 @@ Equality check (a == b) - **Opcode**: 0x04 - **Category**: Compute - Comparators - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input @@ -575,8 +575,8 @@ Less-than check (a < b) - **Opcode**: 0x05 - **Category**: Compute - Comparators - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -596,8 +596,8 @@ Less-than-or-equals check (a <= b) - **Opcode**: 0x06 - **Category**: Compute - Comparators - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -617,8 +617,8 @@ Bitwise AND (a & b) - **Opcode**: 0x07 - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -638,8 +638,8 @@ Bitwise OR (a | b) - **Opcode**: 0x08 - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -659,8 +659,8 @@ Bitwise XOR (a ^ b) - **Opcode**: 0x09 - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -680,8 +680,8 @@ Bitwise NOT (inversion) - **Opcode**: 0x0a - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's input - **dstOffset**: memory offset specifying where to store operation's result @@ -700,8 +700,8 @@ Bitwise leftward shift (a << b) - **Opcode**: 0x0b - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -721,8 +721,8 @@ Bitwise rightward shift (a >> b) - **Opcode**: 0x0c - **Category**: Compute - Bitwise - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **inTag**: The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -742,7 +742,7 @@ Type cast - **Opcode**: 0x0d - **Category**: Type Conversions - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **dstTag**: The [tag/size](./state-model#tags-and-tagged-memory) to tag the destination with but not to check inputs against. - **Args**: - **aOffset**: memory offset of word to cast @@ -762,7 +762,7 @@ Get the address of the currently executing l2 contract - **Opcode**: 0x0e - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.address` @@ -779,7 +779,7 @@ Get the _storage_ address of the currently executing context - **Opcode**: 0x0f - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.storageAddress` @@ -797,7 +797,7 @@ Get the transaction's origination address - **Opcode**: 0x10 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.origin` @@ -814,7 +814,7 @@ Get the address of the sender (caller of the current context) - **Opcode**: 0x11 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.sender` @@ -831,7 +831,7 @@ Get the address of the l1 portal contract - **Opcode**: 0x12 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.portal` @@ -848,7 +848,7 @@ Get the fee to be paid per "L1 gas" - constant for entire transaction - **Opcode**: 0x13 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.feePerL1Gas` @@ -865,7 +865,7 @@ Get the fee to be paid per "L2 gas" - constant for entire transaction - **Opcode**: 0x14 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.feePerL2Gas` @@ -882,7 +882,7 @@ Get the fee to be paid per "DA gas" - constant for entire transaction - **Opcode**: 0x15 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.feePerDaGas` @@ -899,7 +899,7 @@ Get how many contract calls deep the current call context is - **Opcode**: 0x16 - **Category**: Execution Environment - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.contractCallDepth` @@ -917,7 +917,7 @@ Get this rollup's L1 chain ID - **Opcode**: 0x17 - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.chainId` @@ -934,7 +934,7 @@ Get this rollup's L2 version ID - **Opcode**: 0x18 - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.version` @@ -951,7 +951,7 @@ Get this L2 block's number - **Opcode**: 0x19 - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.blocknumber` @@ -968,7 +968,7 @@ Get this L2 block's timestamp - **Opcode**: 0x1a - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.timestamp` @@ -985,7 +985,7 @@ Get the block's beneficiary address - **Opcode**: 0x1b - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.coinbase` @@ -1002,7 +1002,7 @@ Total amount of "L1 gas" that a block can consume - **Opcode**: 0x1c - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.l1GasLimit` @@ -1019,7 +1019,7 @@ Total amount of "L2 gas" that a block can consume - **Opcode**: 0x1d - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.l2GasLimit` @@ -1036,7 +1036,7 @@ Total amount of "DA gas" that a block can consume - **Opcode**: 0x1e - **Category**: Execution Environment - Globals - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.environment.globals.daGasLimit` @@ -1053,7 +1053,7 @@ Copy calldata into memory - **Opcode**: 0x1f - **Category**: Execution Environment - Calldata - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **cdOffset**: offset into calldata to copy from - **copySize**: number of words to copy @@ -1073,7 +1073,7 @@ Remaining "L1 gas" for this call (after this instruction) - **Opcode**: 0x20 - **Category**: Machine State - Gas - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.machineState.l1GasLeft` @@ -1090,7 +1090,7 @@ Remaining "L2 gas" for this call (after this instruction) - **Opcode**: 0x21 - **Category**: Machine State - Gas - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.MachineState.l2GasLeft` @@ -1107,7 +1107,7 @@ Remaining "DA gas" for this call (after this instruction) - **Opcode**: 0x22 - **Category**: Machine State - Gas - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = context.machineState.daGasLeft` @@ -1139,7 +1139,7 @@ Conditionally jump to a location in the bytecode - **Opcode**: 0x24 - **Category**: Machine State - Control Flow - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **loc**: target location conditionally jump to - **condOffset**: memory offset of the operations 'conditional' input @@ -1187,7 +1187,7 @@ Set a memory word from a constant in the bytecode - **Opcode**: 0x27 - **Category**: Machine State - Memory - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **inTag**: The [type/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for SET. - **Args**: - **const**: an N-bit constant value from the bytecode to store in memory (any type except `field`) @@ -1207,7 +1207,7 @@ Move a word from source memory location to destination - **Opcode**: 0x28 - **Category**: Machine State - Memory - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **srcOffset**: memory offset of word to move - **dstOffset**: memory offset specifying where to store that word @@ -1225,7 +1225,7 @@ Move a word (conditionally chosen) from one memory location to another (`d = con - **Opcode**: 0x29 - **Category**: Machine State - Memory - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **aOffset**: memory offset of word 'a' to conditionally move - **bOffset**: memory offset of word 'b' to conditionally move @@ -1246,7 +1246,7 @@ Get the block header as of the specified block number - **Opcode**: 0x2a - **Category**: World State - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **blockNumOffset**: memory offset of the block number input - **dstOffset**: memory offset specifying where to store operation's result's 0th word @@ -1264,7 +1264,7 @@ Load a word from storage - **Opcode**: 0x2b - **Category**: World State - Public Storage - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **slotOffset**: memory offset of the storage slot to load from - **dstOffset**: memory offset specifying where to store operation's result @@ -1283,7 +1283,7 @@ Write a word to storage - **Opcode**: 0x2c - **Category**: World State - Public Storage - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **srcOffset**: memory offset of the word to store - **slotOffset**: memory offset containing the storage slot to store to @@ -1301,7 +1301,7 @@ Reads an L1-to-L2 message - **Opcode**: 0x2d - **Category**: World State - Messaging - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **msgKeyOffset**: memory offset of the message's key - **dstOffset**: memory offset to place the 0th word of the message content @@ -1320,7 +1320,7 @@ Send an L2-to-L1 message - **Opcode**: 0x2e - **Category**: World State - Messaging - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **msgOffset**: memory offset of the message content - **msgSize**: number of words in the message @@ -1337,7 +1337,7 @@ Emit a new note hash to be inserted into the notes tree - **Opcode**: 0x2f - **Category**: World State - Notes & Nullifiers - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **noteHashOffset**: memory offset of the note hash - **Expression**: `context.worldState.newHashes.append(M[noteHashOffset])` @@ -1353,7 +1353,7 @@ Emit a new nullifier to be inserted into the nullifier tree - **Opcode**: 0x30 - **Category**: World State - Notes & Nullifiers - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **nullifierOffset**: memory offset of nullifier - **Expression**: `context.worldState.nullifiers.append(M[nullifierOffset])` @@ -1369,7 +1369,7 @@ Emit an unencrypted log - **Opcode**: 0x31 - **Category**: Accrued Substate - Logging - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **logOffset**: memory offset of the data to log - **logSize**: number of words to log @@ -1386,7 +1386,7 @@ Call into another contract - **Opcode**: 0x32 - **Category**: Control Flow - Contract Calls - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **gasOffset**: offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee - **addrOffset**: address of the contract to call @@ -1424,7 +1424,7 @@ Call into another contract, disallowing World State and Accrued Substate modific - **Opcode**: 0x33 - **Category**: Control Flow - Contract Calls - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **gasOffset**: offset to three words containing `{l1GasLeft, l2GasLeft, daGasLeft}`: amount of gas to provide to the callee - **addrOffset**: address of the contract to call @@ -1460,7 +1460,7 @@ Halt execution within this context (without revert), optionally returning some d - **Opcode**: 0x34 - **Category**: Control Flow - Contract Calls - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **retOffset**: memory offset of first word to return - **retSize**: number of words to return @@ -1482,7 +1482,7 @@ Halt execution within this context as `reverted`, optionally returning some data - **Opcode**: 0x35 - **Category**: Control Flow - Contract Calls - **Flags**: - - **indirect**: Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - **retOffset**: memory offset of first word to return - **retSize**: number of words to return diff --git a/yellow-paper/docs/rollup-circuits/base-rollup.md b/yellow-paper/docs/rollup-circuits/base-rollup.md index 676f37788dd..140f62fd30c 100644 --- a/yellow-paper/docs/rollup-circuits/base-rollup.md +++ b/yellow-paper/docs/rollup-circuits/base-rollup.md @@ -38,7 +38,8 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address + coinbase: EthAddress + fee_recipient: Address } class Header { @@ -311,8 +312,8 @@ def kernel_checks( assert kernel.proof.verify(kernel.public_inputs) tx_context = kernel.public_inputs.constants.tx_context - assert tx_context.chainid == constants.globalVariables.chainid - assert tx_context.version == constants.globalVariables.version + assert tx_context.chain_id == constants.global_variables.chain_id + assert tx_context.version == constants.global_variables.version assert len(kernel.public_inputs.end.private_call_stack) == 0 assert len(kernel.public_inputs.end.public_call_stack) == 0 diff --git a/yellow-paper/docs/rollup-circuits/index.md b/yellow-paper/docs/rollup-circuits/index.md index f22aa2b0b7f..397b16a2941 100644 --- a/yellow-paper/docs/rollup-circuits/index.md +++ b/yellow-paper/docs/rollup-circuits/index.md @@ -4,14 +4,12 @@ title: Rollup Circuits ## Overview -Together with the [validating light node](../cross-chain-communication/index.md) the rollup circuits must ensure that incoming blocks are valid, that state is progressed correctly and that anyone can rebuild the state. +Together with the [validating light node](../l1-smart-contracts/index.md) the rollup circuits must ensure that incoming blocks are valid, that state is progressed correctly and that anyone can rebuild the state. To support this, we construct a single proof for the entire block, which is then verified by the validating light node. This single proof is constructed by recursively merging proofs together in a binary tree structure. This structure allows us to keep the workload of each individual proof small, while making it very parallelizable. This works very well for the case where we want many actors to be able to participate in the proof generation. -The tree structure is outlined below, but the general idea is that we have a tree where all the leaves are transactions (kernel proofs) and through $\log(n)$ steps we can then "compress" them down to just a single root proof. Note that we have three (3) different types of "merger" circuits, namely: +The tree structure is outlined below, but the general idea is that we have a tree where all the leaves are transactions (kernel proofs) and through $\log(n)$ steps we can then "compress" them down to just a single root proof. Note that we have two different types of "merger" circuit, namely: -- The base rollup - - Merges two kernel proofs - The merge rollup - Merges two base rollup proofs OR two merge rollup proofs - The root rollup @@ -93,6 +91,12 @@ To understand what the circuits are doing and what checks they need to apply it Below is a figure of the data structures thrown around for the block proof creation. Note that the diagram does not include much of the operations for kernels, but mainly the data structures that are used for the rollup circuits. + + + + + + ```mermaid classDiagram direction TB @@ -115,7 +119,8 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address + coinbase: EthAddress + fee_recipient: Address } class Header { @@ -379,7 +384,7 @@ graph LR To ensure that state is made available, we could broadcast all of a block's input data as public inputs of the final root rollup proof, but a proof with so many public inputs would be very expensive to verify onchain. Instead we reduce the proof's public inputs by committing to the block's body by iteratively computing a `TxsHash` and `OutHash` at each rollup circuit iteration. AT the final iteration a `body_hash` is computed committing to the complete body. -To check that this body is published an Aztec node can reconstruct the `body_hash` from available data. Since we define finality as the point where the block is validated and included in the state of the [validating light node](../cross-chain-communication/index.md), we can define a block as being "available" if the validating light node can reconstruct the commitment `body_hash`. +To check that this body is published an Aztec node can reconstruct the `body_hash` from available data. Since we define finality as the point where the block is validated and included in the state of the [validating light node](../l1-smart-contracts/index.md), we can define a block as being "available" if the validating light node can reconstruct the commitment `body_hash`. Since we strive to minimize the compute requirements to prove blocks, we amortize the commitment cost across the full tree. We can do so by building merkle trees of partial "commitments", whose roots are ultimately computed in the final root rollup circuit. The `body_hash` is then computed from the roots of these trees, together with incoming messages. 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. While the `TxsHash` implicitly includes the `l2_to_l1_msgs` we construct it separately since the `l2_to_l1_msgs` must be available to the L1 contract directly and not just proven available. This is not a concern when using L1 calldata as the data layer, but is a concern when using alternative data layers such as [Celestia](https://celestia.org/) or [Blobs](https://eips.ethereum.org/EIPS/eip-4844). diff --git a/yellow-paper/docs/rollup-circuits/merge-rollup.md b/yellow-paper/docs/rollup-circuits/merge-rollup.md index 1a83e47267d..ae5468ca5af 100644 --- a/yellow-paper/docs/rollup-circuits/merge-rollup.md +++ b/yellow-paper/docs/rollup-circuits/merge-rollup.md @@ -29,7 +29,8 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address + coinbase: EthAddress + fee_recipient: Address } class ConstantRollupData { diff --git a/yellow-paper/docs/rollup-circuits/root-rollup.md b/yellow-paper/docs/rollup-circuits/root-rollup.md index 6b65b252a79..c75efad220a 100644 --- a/yellow-paper/docs/rollup-circuits/root-rollup.md +++ b/yellow-paper/docs/rollup-circuits/root-rollup.md @@ -9,7 +9,7 @@ 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](../cross-chain-communication/index.md) that we put on L1. We will cover it in more detail in the [cross-chain communication](../cross-chain-communication/index.md) section. +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. :::info Squishers This might practically happen through a series of "squisher" circuits that will wrap the proof in another proof that is cheaper to verify on-chain. For example, wrapping a ultra-plonk proof in a standard plonk proof. @@ -39,8 +39,8 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address -} + coinbase: EthAddress + fee_recipient: Address} class Header { last_archive: Snapshot @@ -214,4 +214,4 @@ def RootRollupCircuit( ) ``` -The `RootRollupPublicInputs` can then be used together with `Body` to build a `ProvenBlock` which can be used to convince the [validating light node](../cross-chain-communication/index.md) of state progression. +The `RootRollupPublicInputs` can then be used together with `Body` to build a `ProvenBlock` which can be used to convince the [validating light node](../l1-smart-contracts/index.md) of state progression. diff --git a/yellow-paper/docs/state/archive.md b/yellow-paper/docs/state/archive.md index 3ea15936084..cd9e5feca77 100644 --- a/yellow-paper/docs/state/archive.md +++ b/yellow-paper/docs/state/archive.md @@ -1,14 +1,47 @@ --- -title: Archive +title: Archive Tree --- -# Archive +The Archive Tree is an [append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees) that stores the Headers (see the diagram below) of all previous blocks in the chain as its leaves. -The Archive is an [append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees) that stores the headers of all previous blocks in the chain as its leaves. +For most chains this is not required since they are always executing at the head of the chain. However, private execution relies on proofs generated by the user, and since users don't know the current head they must base their proofs on historical state. By including all prior headers (which include commitments to the state) the Archive Tree allows us to easily prove that the historic state that a transaction was proven upon is valid. -For most chains this is not required since they are always executing at the head of the chain. However, private execution relies on proofs generated by the user, and since users don't know the current head they must base their proofs on historical state. By including all prior headers (which include commitments to the state) the Archive allows us to easily prove that the historic state that a transaction was proven upon is valid. +Furthermore, since each Header includes a snapshot of the Archive Tree as at the time of insertion, as well as commitments to the Header's block content and global variables, we can use the Archive Tree to prove statements about the state at any given block or even transactions that occurred at specific blocks. -Furthermore, since the Headers include a snapshot of the Archive at the time of insertion, as well as commitments to the block content and global variables, we can use it to prove statements about the state at any given block or even transactions that occurred at specific blocks. + + + + + + + + + ```mermaid classDiagram @@ -33,7 +66,8 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address + coinbase: EthAddress + fee_recipient: Address } class Header { @@ -80,9 +114,9 @@ class Body { } Body *-- "m" TxEffect -class Archive { +class ArchiveTree { type: AppendOnlyMerkleTree leaves: List~Header~ } -Archive *.. "m" Header : leaves +ArchiveTree *.. "m" Header : leaves ``` diff --git a/yellow-paper/docs/state/index.md b/yellow-paper/docs/state/index.md index 0ac42fec0d1..e84259b8623 100644 --- a/yellow-paper/docs/state/index.md +++ b/yellow-paper/docs/state/index.md @@ -2,22 +2,26 @@ title: State --- + + # State The global state is the set of data that makes up Aztec - it is persistent and only updates when new blocks are added to the chain. -The state consists of multiple different categories of data with varying requirements. What all of the categories have in common is that they need strong integrity guarantees and efficient membership proofs. Like most other blockchains, this can be enforced by structuring the data as leafs in Merkle trees. +The state consists of multiple different categories of data with varying requirements. What all of the categories have in common is that they need strong integrity guarantees and efficient membership proofs. Like most other blockchains, this can be enforced by structuring the data as leaves in Merkle trees. -However, unlike most other blockchains, our contract state cannot use a Merkle tree as a key-value store for each contracts data. The reason for this is that we have both private and public state; while public state could be stored in a key-value tree, private state cannot, as doing so would leak information whenever the private state is updated, even if encrypted. +However, unlike most other blockchains, our contract state cannot use a Merkle tree as a key-value store for each contract's data. The reason for this is that we have both private and public state; while public state could be stored in a key-value tree, private state cannot, as doing so would leak information whenever the private state is updated, even if encrypted. -To work around this, we use a two-tree approach for state that can be used privately. Namely we have one (or more) tree(s) where data is added to (sometimes called a data tree), and a second tree where we "nullify" or mark the data as deleted. This allows us to "update" a leaf by adding a new leaf to the date trees, and add the nullifier of the old leaf to the second tree (the nullifier tree). That way we can show that the new leaf is the "active" one, and that the old leaf is "deleted". +To work around this, we use a two-tree approach for state that can be used privately. Namely we have one (or more) tree(s) where data is added to (sometimes called a data tree), and a second tree where we "nullify" or mark the data as deleted. This allows us to "update" a leaf by adding a new leaf to the data trees, and add the nullifier of the old leaf to the second tree (the nullifier tree). That way we can show that the new leaf is the "active" one, and that the old leaf is "deleted". -When dealing with private data, only the hash of the data is stored in the leaf in our data tree and we must setup a derivation mechanism that ensures nullifiers can be computed deterministically from the pre-image (the data that was hashed). This way, no-one can tell what data is stored in the leaf (unless they already know it), and therefore won't be able to derive the nullifier and tell if the leaf is active or deleted. +When dealing with private data, only the hash of the data is stored in the leaf in our data tree and we must set up a derivation mechanism that ensures nullifiers can be computed deterministically from the pre-image (the data that was hashed). This way, no-one can tell what data is stored in the leaf (unless they already know it), and therefore won't be able to derive the nullifier and tell if the leaf is active or deleted. Convincing someone that a piece of data is active can then be done by proving its membership in the data tree, and that it is not deleted by proving its non-membership in the nullifier tree. This ability to efficiently prove non-membership is one of the extra requirements we have for some parts of our state. To support the requirements most efficiently, we use two families of Merkle trees: - The [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees), which supports efficient membership proofs, -- The [Indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees), which supports efficient membership and non-membership proofs but increases the cost of adding leafs. +- The [Indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees), which supports efficient membership and non-membership proofs but increases the cost of adding leaves. ### Private State Access @@ -43,16 +47,24 @@ A side-effect of this also means that if multiple users are "sharing" their note ## State Categories + + Below is a short description of the state catagories (trees) and why they have the type they have. -- [**Note Hashes**](./note-hash-tree.md): A set of hashes (commitments) of the individual blobs of contract data (we call these blobs of data notes). New notes can be created and their hashes inserted through contract execution. We need to support efficient membership proofs as any read will require one to prove validity. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees), storing the note hashes as leafs. +- [**Note Hashes**](./note-hash-tree.md): A set of hashes (commitments) of the individual blobs of contract data (we call these blobs of data notes). New notes can be created and their hashes inserted through contract execution. We need to support efficient membership proofs as any read will require one to prove validity. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees), storing the note hashes as leaves. - [**Nullifiers**](./nullifier-tree.md): A set of nullifiers for notes that have been spent. We need to support efficient non-membership proofs since we need to check that a note has not been spent before it can be used. The set is represented as an [Indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees). - [**Public Data**](./public-data-tree.md): The key-value store for public contract state. We need to support both efficient membership and non-membership proofs! We require both, since the tree is "empty" from the start. Meaning that if the key is not already stored (non-membership), we need to insert it, and if it is already stored (membership) we need to just update the value. - **Contracts**: The set of deployed contracts. We need to support efficient membership proofs as we need to check that a contract is deployed before we can interact with it. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). - **L1 to L2 Messages**: The set of messages sent from L1 to L2. The set itself only needs to support efficient membership proofs, so we can ensure that the message was correctly sent from L1. However, it utilizes the Nullifier tree from above to ensure that the message cannot be processed twice. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). -- [**Archive**](./archive.md): The set of block headers that have been processed. We need to support efficient membership proofs as this is used in private execution to get the roots of the other trees. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). +- [**Archive Tree**](./archive.md): The set of block headers that have been processed. We need to support efficient membership proofs as this is used in private execution to get the roots of the other trees. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). + +To recall, the global state in Aztec is represented by a set of Merkle trees: the [Note Hash tree](./note-hash-tree.md), [Nullifier tree](./nullifier-tree.md), and [Public Data tree](./public-data-tree.md) reflect the latest state of the chain, while the L1 to L2 message tree allows for [cross-chain communication](../l1-smart-contracts/#l2-outbox) and the [Archive Tree](./archive.md) allows for historical state access. -To recall, the global state in Aztec is represented by a set of Merkle trees: the [Note Hash tree](./note-hash-tree.md), [Nullifier tree](./nullifier-tree.md), and [Public Data tree](./public-data-tree.md) reflect the latest state of the chain, while the L1 to L2 message tree allows for [cross-chain communication](../cross-chain-communication/#l2-outbox) and the [Archive](./archive.md) allows for historical state access. + ```mermaid classDiagram @@ -77,11 +89,12 @@ class GlobalVariables { timestamp: Fr version: Fr chain_id: Fr - coinbase: Address + coinbase: EthAddress + fee_recipient: Address } class Header { - last_archive: Snapshot + previous_archive_tree: Snapshot body_hash: Fr[2] state: StateReference global_variables: GlobalVariables @@ -124,11 +137,11 @@ class Body { } Body *-- "m" TxEffect -class Archive { +class ArchiveTree { type: AppendOnlyMerkleTree leaves: List~Header~ } -Archive *.. "m" Header : leaves +ArchiveTree *.. "m" Header : leaves class NoteHashTree { @@ -179,7 +192,7 @@ class NullifierTree { NullifierTree *.. "m" NullifierPreimage : leaves class State { - archive: Archive + archive_tree: ArchiveTree note_hash_tree: NoteHashTree nullifier_tree: NullifierTree public_data_tree: PublicDataTree @@ -187,7 +200,7 @@ class State { l1_to_l2_message_tree: L1ToL2MessageTree } State *-- L1ToL2MessageTree : l1_to_l2_message_tree -State *-- Archive : archive +State *-- ArchiveTree : archive_tree State *-- NoteHashTree : note_hash_tree State *-- NullifierTree : nullifier_tree State *-- PublicDataTree : public_data_tree diff --git a/yellow-paper/docs/state/note-hash-tree.md b/yellow-paper/docs/state/note-hash-tree.md index 5ff8c0ad3fb..78bab7bb6e3 100644 --- a/yellow-paper/docs/state/note-hash-tree.md +++ b/yellow-paper/docs/state/note-hash-tree.md @@ -1,12 +1,12 @@ # Note Hash Tree -The Note Hash tree is an [append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees) that stores siloed note hashes as its elements. Each element in the tree is a 254-bit altBN-254 scalar field element. This tree is part of the global state, and allows to prove existence of private notes via Merkle membership proofs. +The Note Hash tree is an [append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees) that stores [siloed](./tree-implementations.md#siloing-leaves) note hashes as its elements. Each element in the tree is a 254-bit altBN-254 scalar field element. This tree is part of the global state, and is used to prove existence of private notes via Merkle membership proofs. -Note commitments are immutable once created, since notes cannot be modified. Still, notes can be consumed, which means they can no longer be used. To preserve privacy, a consumed note is not removed from the tree, otherwise it would be possible to link the transaction that created a note with the one that consumed it. Instead, a note is consumed by emitting a deterministic [nullifier](./nullifier-tree.md). +Note commitments are immutable once created. Still, notes can be consumed ("read") by functions. To preserve privacy, a consumed note is not removed from the tree, otherwise it would be possible to link the transaction that created a note with the one that consumed it. Instead, a note is consumed by emitting a deterministic [nullifier](./nullifier-tree.md). -Contracts emit new note commitments via the `new_commitments` in the `CircuitPublicInputs`, which are subsequently [siloed](./tree-implementations.md#siloing-leaves) per contract by the Kernel circuit. Siloing the commitment ensures that a contract cannot emit a commitment for a note that could be used for a different contract. +Contracts emit new note commitments via the `new_commitments` in the `CircuitPublicInputs` , which are subsequently [siloed](./tree-implementations.md#siloing-leaves) by contract address by the Kernel circuit. Siloing the commitment ensures that a malicious contract cannot create notes for (that is, modify the state of) another contract. -The Kernel circuit also guarantees uniqueness of commitments by further hashing them with a nonce, derived from the transaction identifier and the index of the commitment within the transaction. Uniqueness means that a note with the same contents can be emitted more than once, and each instance can be independently nullified. Without uniqueness, two notes with the same content would yield the same commitment and nullifier, so nullifying one of them would flag the second one as nullified as well. +The Kernel circuit also guarantees uniqueness of commitments by further hashing them with a nonce, derived from the transaction identifier and the index of the commitment within the transaction's array of newly-created note hashes. Uniqueness means that a note with the same contents can be emitted more than once, and each instance can be independently nullified. Without uniqueness, two notes with the same content would yield the same commitment and nullifier, so nullifying one of them would render the second one as nullified as well. The pseudocode for siloing and making a commitment unique is the following, where each `hash` operation is a Pedersen hash with a unique generator index, indicated by the constant in all caps. @@ -18,8 +18,8 @@ fn compute_unique_siloed_commitment(commitment, contract, transaction): return hash([nonce, siloed_commitment], UNIQUE_COMMITMENT) ``` -The unique siloed commitment of a note is included in the [transaction `data`](../transactions/tx-object.md), and then included into the Note Hash tree by the sequencer as the transaction is included in a block. +The unique siloed commitment of a note is included in the [transaction `data`](../transactions/tx-object.md), and then inserted into the Note Hash tree by the sequencer as the transaction is included in a block. -The protocol does not enforce any constraints to the commitment emitted by an application. This means that applications are responsible for including a `randomness` field in the note hash to make the commitment _hiding_ in addition to _binding_. If an application does not include randomness, and the note preimage can be guessed by an attacker, it makes the note vulnerable to preimage attacks, since the siloing and uniqueness steps do not provide hiding. +The protocol does not enforce any constraints on any note hashes emitted by an application. This means that applications are responsible for including a `randomness` field in the note hash to make the commitment _hiding_ in addition to _binding_. If an application does not include randomness, and the note preimage can be guessed by an attacker, it makes the note vulnerable to preimage attacks, since the siloing and uniqueness steps do not provide hiding. Furthermore, since there are no constraints to the commitment emitted by an application, an application can emit any value whatsoever as a `new_commitment`, including values that do not map to a note hash. diff --git a/yellow-paper/docs/state/nullifier-tree.md b/yellow-paper/docs/state/nullifier-tree.md index 08806e2cb26..036b69cff01 100644 --- a/yellow-paper/docs/state/nullifier-tree.md +++ b/yellow-paper/docs/state/nullifier-tree.md @@ -1,10 +1,22 @@ # Nullifier Tree -The Nullifier tree is an [indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees) that stores nullifier values. Each value stored in the tree is a 254-bit altBN-254 scalar field element. This tree is part of the global state, and allows to prove non-existence of a nullifier when a note is consumed. +The Nullifier tree is an [indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees) that stores nullifier values. Each value stored in the tree is a 254-bit altBN-254 scalar field element. This tree is part of the global state, and is primarily used to prove non-existence of a nullifier when a note is consumed (as a way of preventing double-spend). -Nullifiers are asserted to be unique during insertion, by checking that the inserted value is not equal to the value and next-value stored in the prior node in the indexed tree. Any attempt to insert a duplicated value is rejected. +In addition to storing nullifiers of notes, the nullifier tree is more generally useful to prevent any action from being repeated twice. This includes preventing re-initialization of state variables, and [re-deployment of contracts](../contract-deployment/instances.md). -Contracts emit new nullifiers via the `new_nullifiers` in the `CircuitPublicInputs`. Same as elements in the [Note Hash tree](./note-hash-tree.md), nullifiers are [siloed](./tree-implementations.md#siloing-leaves) per contract by the Kernel circuit before being inserted in the tree, which ensures that a contract cannot emit nullifiers that affect other contracts. +Nullifiers are asserted to be unique during insertion, by checking that the inserted value is not equal to the value and next-value stored in the prior leaf in the indexed tree. Any attempt to insert a duplicated value is rejected. + +Contracts emit new nullifiers via the `new_nullifiers` field of the `CircuitPublicInputs` ABI . Similarly to elements in the [Note Hash tree](./note-hash-tree.md), nullifiers are [siloed](./tree-implementations.md#siloing-leaves) by contract address, by the Kernel circuit, before being inserted into the tree. This ensures that a contract cannot emit the nullifiers of other contracts' state variables! + + + + ``` fn compute_siloed_nullifier(nullifier, contract): @@ -18,3 +30,17 @@ Nullifiers provide privacy by being computed using a deterministic secret value, Applications are not constrained by the protocol on how the nullifier for a note is computed. It is responsibility of the application to guarantee determinism in calculating a nullifier, otherwise the same note could be spent multiple times. Furthermore, nullifiers can be emitted by an application just to ensure that an action can be executed only once, such as initializing a value, and are not required to be linked to a note commitment. + + diff --git a/yellow-paper/docs/state/public-data-tree.md b/yellow-paper/docs/state/public-data-tree.md index 671455a5a6a..1c48c23a4d5 100644 --- a/yellow-paper/docs/state/public-data-tree.md +++ b/yellow-paper/docs/state/public-data-tree.md @@ -1,10 +1,15 @@ # Public Data Tree -The Public Data tree is an [indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees) that stores public-state key-value data. Each item stored in the tree is a key-value pair, where both key and value are 254-bit altBN-254 scalar field elements. Items are sorted based on their key, so each indexed tree leaf contains a tuple with the key, the value, the next higher key, and the index in the tree for the next higher key. This tree is part of the global state, and is updated by the sequencer during the execution of public functions. +The Public Data tree is an [indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees) that stores public-state. Each item stored in the tree is a key-value pair, where both key and value are 254-bit altBN-254 scalar field elements. Items are sorted based on their key, so each indexed tree leaf contains a tuple with the key, the value, the next-highest key, and the index in the tree for the next-highest key. This tree is part of the global state, and is updated by the sequencer during the execution of public functions. -The Public Data tree is implemented using an indexed Merkle tree instead of a sparse Merkle tree in order to reduce the tree height. A lower height means shorter membership proofs. +An indexed Merkle tree is ued instead of a sparse Merkle tree in order to reduce the tree height. A lower height means shorter membership proofs. -Keys in the Public Data tree are [siloed](./tree-implementations.md#siloing-leaves) using the contract address, to prevent a contract from overwriting public state for another contract. +Keys in the Public Data tree are [siloed](./tree-implementations.md#siloing-leaves) using the contract address, to prevent a contract from overwriting the public state of another contract. + + ``` fn compute_siloed_public_data_item(key, value, contract): @@ -12,8 +17,27 @@ fn compute_siloed_public_data_item(key, value, contract): return [siloed_key, value] ``` -When reading a key from the Public Data tree, the key may or may not be present. If the key is not present, then a non-membership proof is produced, and the value is assumed to be zero. When a key is written to, either a new node is appended to the tree if the key was not present, or its value is overwritten if it was. +When attempting to read a key from the Public Data tree, the key may or may not be present. If the key is not present, then a non-membership proof can be produced. When a key is written to, either a new node is appended to the tree if the key was not present, or its value is overwritten if it was. Public functions can read from or write to the Public Data tree by emitting `contract_storage_read` and `contract_storage_update_requests` in the `PublicCircuitPublicInputs`. The Kernel circuit then siloes these requests per contract. Contracts can store arbitrary data at a given key, which is always stored as a single field element. Applications are responsible for interpreting this data. Should an application need to store data larger than a single field element, they are responsible for partitioning it across multiple keys. + + diff --git a/yellow-paper/docs/state/tree-implementations.md b/yellow-paper/docs/state/tree-implementations.md index 0a698eb2de4..20d30aaccba 100644 --- a/yellow-paper/docs/state/tree-implementations.md +++ b/yellow-paper/docs/state/tree-implementations.md @@ -4,15 +4,15 @@ Aztec relies on two Merkle tree implementations in the protocol: append-only and ## Append-only Merkle trees -In an append-only Merkle tree new leaves are inserted in order from left to right. Existing leaf values are immutable and cannot be modified. These tree are useful to represent historic data, as new entries are added as new transactions and blocks are processed, and historic data is not altered. +In an append-only Merkle tree, new leaves are inserted in order from left to right. Existing leaf values are immutable and cannot be modified. These trees are useful to represent historical data, as historical data is not altered, and new entries can be added as new transactions and blocks are processed. -Append-only trees allow for more efficient syncing than sparse trees, since clients can sync from left to right starting with their last known value. Updates to the tree root from new leaves can be computed just by keeping the rightmost boundary of the tree, and batch insertions can be computed with fewer hashes than in a sparse tree. Append-only trees also provide cheap historic snapshots, as older roots can be computed by completing the merkle path from a past left subtree with an empty right subtree. +Append-only trees allow for more efficient syncing than sparse trees, since clients can sync from left to right starting with their last known value. Updates to the tree root, when inserting new leaves, can be computed from the rightmost "frontier" of the tree (i.e., from the sibling path of the rightmost nonzero leaf). Batch insertions can be computed with fewer hashes than in a sparse tree. The historical snapshots of append-only trees also enable efficient membership proofs; as older roots can be computed by completing the merkle path from a past left subtree with an empty right subtree. ## Indexed Merkle trees -Indexed Merkle trees, introduced [here](https://eprint.iacr.org/2021/1263.pdf), allow for proofs of non-inclusion more efficiently than sparse Merkle trees. Each leaf in the tree is a tuple with the leaf value, the next higher value in the tree, and the index of the leaf where that value is stored. New nodes are inserted left to right, as in the append-only tree, but existing nodes can be modified to update the next value and its pointer. Indexed Merkle trees behave as a Merkle tree over a sorted linked list. +Indexed Merkle trees, introduced [here](https://eprint.iacr.org/2021/1263.pdf), allow for proofs of non-inclusion more efficiently than sparse Merkle trees. Each leaf in the tree is a tuple of: the leaf value, the next-highest value in the tree, and the index of the leaf where that next-highest value is stored. New leaves are inserted from left to right, as in the append-only tree, but existing leaves can be _modified_ to update the next-highest value and next-highest index (a.k.a. the "pointer") if a new leaf with a "closer value" is added to the tree. An Indexed Merkle trees behaves as a Merkle tree over a sorted linked list. -Assuming the indexed Merkle tree invariants hold, proving non-membership of a value `x` then requires a membership proof of the node with value lower than `x` and a next higher 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. +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](https://docs.aztec.network/concepts/advanced/data_structures/indexed_merkle_tree) for more details on how insertions, updates, and membership proofs are executed on an Indexed Merkle tree. @@ -20,6 +20,6 @@ Refer to [this page](https://docs.aztec.network/concepts/advanced/data_structure ## Siloing leaves -In several trees in the protocol we indicate that its leaves are "siloed". This refers to hashing the leaf value with a siloing value before inserting it in the tree. The siloing value is typically an identifier of the contract that produced the value. This allows us to store disjoint "domains" within the same tree, ensuring that a value emitted from one domain cannot affect others. +In several trees in the protocol we indicate that its leaves are "siloed". This refers to hashing the leaf value with some other "siloing" value before inserting it into the tree. The siloing value is typically the contract address of the contract that produced the value. This allows us to store disjoint "domains" within the same tree, ensuring that a value emitted from one domain cannot affect others. -To guarantee the siloing of leaf values, siloing is performed by a trusted protocol circuit, such as the kernel or rollup circuits, and not by an application circuit. Siloing is performed by Pedersen hashing the contract address and the value. +To guarantee the siloing of leaf values, siloing is performed by a trusted protocol circuit, such as a kernel or rollup circuit, and not by an application circuit. diff --git a/yellow-paper/docs/transactions/index.md b/yellow-paper/docs/transactions/index.md index 732cfea62c5..efd5ae8b468 100644 --- a/yellow-paper/docs/transactions/index.md +++ b/yellow-paper/docs/transactions/index.md @@ -6,9 +6,9 @@ title: Transactions A transaction is the minimal action that changes the state of the network. Transactions in Aztec have a private and a public component, where the former is executed in the user's private execution environment (PXE) and the latter by the sequencer. -A transaction is also split into three phases to [support authorization abstraction and fee payments](../gas-and-fees/gas-and-fees.md#fees): a validation and fee preparation phase, a main execution phase, and fee distribution phase. +A transaction is also split into three phases to [support authorization abstraction and fee payments](../gas-and-fees/index.md#fees): a validation and fee preparation phase, a main execution phase, and fee distribution phase. -Users initiate a transaction by sending a _transaction request_ to their local PXE, which [locally simulates and proves the transaction](./local-execution.md) and returns a [_transaction_ object](./tx-object.md) identified by a [_transaction hash_](./tx-object.md#transaction-hash). This transaction object is then broadcasted to the network via an Aztec Node, which checks its [validity](./validity.md), and eventually picked up by a sequencer who [executes the public component of the transaction](./public-execution.md) and includes it in a block. +Users initiate a transaction by sending a `transaction_request` to their local PXE, which [locally simulates and proves the transaction](./local-execution.md) and returns a [`transaction_object`](./tx-object.md#transaction-object-struct) identified by a [`transaction_hash`](./tx-object.md#transaction-hash). This transaction object is then broadcast to the network via an Aztec Node, which checks its [validity](./validity.md), and is eventually picked up by a sequencer who [executes the public component of the transaction](./public-execution.md) and includes it in a block. import DocCardList from '@theme/DocCardList'; diff --git a/yellow-paper/docs/transactions/local-execution.md b/yellow-paper/docs/transactions/local-execution.md index bca926136da..77f7a02ec7e 100644 --- a/yellow-paper/docs/transactions/local-execution.md +++ b/yellow-paper/docs/transactions/local-execution.md @@ -2,6 +2,18 @@ Transactions are initiated via a _transaction execution request_ sent from the user to their local _private execution environment_ (PXE). The PXE first executes the transaction locally in a _simulation_ step, and then generates a _zero-knowledge proof_ of correct execution. The PXE is then responsible for converting a _transaction execution request_ into a [_transaction_](./tx-object.md) ready to be broadcasted to the network. + + ## Execution request A transaction execution request has the following structure. Note that, since Aztec uses full native account abstraction where every account is backed by a contract, a transaction execution request only needs to provide the contract address, function, and arguments of the initial call; nonces and signatures are arguments to the call, and thus opaque to the protocol. @@ -9,18 +21,18 @@ A transaction execution request has the following structure. Note that, since Az | Field | Type | Description | |----------|----------|----------| -| origin | AztecAddress | Address of the contract where the transaction is initiated. | -| functionSelector | Field | Selector (identifier) of the function to be called as entrypoint in the origin contract. | -| argsHash | Field | Hash of the arguments to be used for calling the entrypoint function. | -| txContext | TxContext | Includes contract deployment data (if this tx is used to deploy a contract), chain id, and protocol version. | -| packedArguments | PackedArguments[] | Preimages for argument hashes. When executing a function call with the hash of the arguments, the PXE will look for the preimage of that hash in this list, and expand the arguments to execute the call. | -| authWitnesses | AuthWitness[] | Authorization witnesses. When authorizing an action identified by a hash, the PXE will look for the authorization witness identified by that hash and provide that value to the account contract. | +| `origin` | `AztecAddress` | Address of the contract where the transaction is initiated. | +| `functionSelector` | u32 | Selector (identifier) of the function to be called as entrypoint in the origin contract. | +| `argsHash` | `Field` | Hash of the arguments to be used for calling the entrypoint function. | +| `txContext` | `TxContext` | Includes chain id, and protocol version. | +| `packedArguments` | `PackedArguments[]` | Preimages for argument hashes. When executing a function call with the hash of the arguments, the PXE will look for the preimage of that hash in this list, and expand the arguments to execute the call. | +| `authWitnesses` | `AuthWitness[]` | Authorization witnesses. When authorizing an action identified by a hash, the PXE will look for the authorization witness identified by that hash and provide that value to the account contract. | ## Simulation step -Upon receiving a transaction execution request to _simulate_, the PXE will locally execute the function identified by the given `functionSelector` in the given `origin` contract with the arguments committed to by `argsHash`. We refer to this function as the _entrypoint_. During execution, contracts may request authorization witnesses or expanded arguments from the _execution oracle_, which are answered with the `packedArguments` and `authWitnesses` from the request. +Upon receiving a transaction execution request to _simulate_, the PXE will locally execute the function identified by the given `functionSelector` in the given `origin` contract with the arguments committed to by `argsHash`. We refer to this function as the _entrypoint_. During execution, contracts may request authorization witnesses or expanded arguments from the _execution oracle_ , which are answered with the `packedArguments` and `authWitnesses` from the request. -The _entrypoint_ may enqueue additional function calls, either private or public, and so forth. The simulation step will always execute all private functions in the call stack until emptied. The result of the simulation is a [_transaction_](./tx-object.md) object without an associated _proof_ which is returned to the application that requested the simulation. +The _entrypoint_ may enqueue additional function calls, either private or public. The simulation step will always execute all private functions in the call stack until emptied. The result of the simulation is a [_transaction_](./tx-object.md) object without an associated _proof_ which is returned to the application that requested the simulation. In terms of circuitry, the simulation step must execute all application circuits that correspond to private function calls, and then execute the private kernel circuit until the private call stack is empty. Note that circuits are only executed, there is no witness generation or proving involved. diff --git a/yellow-paper/docs/transactions/public-execution.md b/yellow-paper/docs/transactions/public-execution.md index 534f47f8b99..0fb55ab35a7 100644 --- a/yellow-paper/docs/transactions/public-execution.md +++ b/yellow-paper/docs/transactions/public-execution.md @@ -4,12 +4,12 @@ Transactions have a _public execution_ component. Once a transaction is picked u ## Bytecode -Unlike private functions, which are native circuits, public functions in the Aztec Network are specified in Brillig, a zkVM-friendly bytecode. This bytecode is executed and proven in the Brillig public virtual machine. Each function call is a run of the virtual machine, and a _public kernel circuit_ aggregates these calls and produces a final proof for the transaction, which also includes the _private kernel circuit_ proof of the transaction generated during [local execution](./local-execution.md). +Unlike private functions, which are native circuits, public functions in the Aztec Network are specified in AVM bytecode . This bytecode is executed and proven in the Aztec Virtual Machine. Each enqueued public function spawns a new instance of the AVM, and a _public kernel circuit_ aggregates these calls and produces a final proof of the transaction, which also includes the _private kernel circuit_ proof of the transaction generated during [local execution](./local-execution.md). ## State -Since public execution is run by the sequencer, it is run on the state of the chain as it is when the transaction is included in the block. Public functions operate on _public state_, an updateable key-value mapping, instead of notes. +Since public execution is run by the sequencer, it is run on the very-latest state of the chain as it is when the transaction is included in the block. Public functions operate on [_public state_](../state/public-data-tree.md), an updateable key-value mapping, instead of notes. ## Reverts -Note that, unlike local private execution, public execution can _revert_ due to a failed assertion, running out of gas, trying to call a non-existing function, or other failures. If this happens, the sequencer halts execution and discards all side effects from the [transaction payload phase](../gas-and-fees/gas-and-fees.md#transaction-payload). The transaction is still included in the block and pays fees, but is flagged as reverted. +Note that, unlike local private execution, public execution can _revert_ due to a failed assertion, running out of gas, trying to call a non-existing function, or other failures. If this happens, the sequencer halts execution and discards all side effects from the [transaction payload phase](../gas-and-fees/index.md#transaction-payload). The transaction is still included in the block and pays fees, but is flagged as reverted. diff --git a/yellow-paper/docs/transactions/tx-object.md b/yellow-paper/docs/transactions/tx-object.md index a5cca0f2485..29c6c9d33a6 100644 --- a/yellow-paper/docs/transactions/tx-object.md +++ b/yellow-paper/docs/transactions/tx-object.md @@ -2,18 +2,35 @@ The transaction object is the struct broadcasted to the p2p network, generated by [_local execution_](./local-execution.md) by the user's PXE. Sequencers pick up transactions from the p2p network to include in a block. + + ## Transaction object struct The fields of a transaction object are the following: + | Field | Type | Description | |----------|----------|----------| -| data | PrivateKernelPublicInputsFinal | Public inputs (ie output) of the last iteration of the private kernel circuit for this transaction. | -| proof | Buffer | Zero-knowledge honk proof for the last iteration of the private kernel circuit for this transaction. | -| encryptedLogs | Buffer[][] | Encrypted logs emitted per function in this transaction. Position `i` contains the encrypted logs emitted by the `i`-th function execution. | -| unencryptedLogs | Buffer[][] | Equivalent to the above but for unencrypted logs. | -| enqueuedPublicFunctionCalls | PublicCallRequest[] | List of public function calls to run during public execution. | -| newContracts | ExtendedContractData[] | List of new contracts to be deployed as part of this transaction. | +| data | PrivateKernelPublicInputsFinal | Public inputs (ie output) of the last iteration of the private kernel circuit for this transaction. | +| proof | Buffer | Zero-knowledge honk proof for the last iteration of the private kernel circuit for this transaction. | +| encryptedLogs | Buffer[][] | Encrypted logs emitted per function in this transaction. Position `i` contains the encrypted logs emitted by the `i`-th function execution. | +| unencryptedLogs | Buffer[][] | Equivalent to the above but for unencrypted logs. | +| enqueuedPublicFunctionCalls | PublicCallRequest[] | List of public function calls to run during public execution. | +| newContracts | ExtendedContractData[] | List of new contracts to be deployed as part of this transaction. | ### Private kernel public inputs final @@ -21,6 +38,7 @@ Output of the last iteration of the private kernel circuit. Includes _accumulate **Accumulated data** + | Field | Type | Description | |-------|------|-------------| | aggregationObject | AggregationObject | Aggregated proof of all the previous kernel iterations. | @@ -39,6 +57,7 @@ Output of the last iteration of the private kernel circuit. Includes _accumulate **Block header** + | Field | Type | Description | |-------|------|-------------| | noteHashTreeRoot | Field | Root of the note hash tree at the time of when this information was assembled. | @@ -52,22 +71,26 @@ Output of the last iteration of the private kernel circuit. Includes _accumulate ### Public call request + + Each _public call request_ is the preimage of a public call stack item in the transaction's `data`, and has the following fields: + | Field | Type | Description | |----------|----------|----------| -| contractAddress | AztecAddress | Address of the contract on which the function is invoked. | -| callContext | CallContext | Includes function selector and caller. | -| args | Field[] | Arguments to the function call. | +| contractAddress | AztecAddress | Address of the contract on which the function is invoked. | +| callContext | CallContext | Includes function selector and caller. | +| args | Field[] | Arguments to the function call. | | sideEffectCounter | number? | Optional counter for ordering side effects of this function call. | ### Extended contract data Each _extended contract data_ corresponds to a contract being deployed by the transaction, and has the following fields: + | Field | Type | Description | |----------|----------|----------| -| address | AztecAddress | Address where the contract is to be deployed. | +| address | AztecAddress | Address where the contract is to be deployed. | | portalAddress | EthereumAddress | Portal address on L1 for this contract (zero if none). | | bytecode | Buffer | Encoded Brillig bytecode for all public functions in the contract. | | publicKey | PublicKey | Master public encryption key for this contract (zero if none). | @@ -75,11 +98,16 @@ Each _extended contract data_ corresponds to a contract being deployed by the tr ## Transaction hash -A transaction is identified by its _transaction hash_. In order to be able to identify a transaction before it has been locally executed, the hash is computed from its [_transaction execution request_](./local-execution.md#execution-request) by hashing: +A transaction is identified by its `transaction_hash`. In order to be able to identify a transaction before it has been locally executed, the hash is computed from its [_transaction execution request_](./local-execution.md#execution-request) by hashing: + + - `origin` - `functionSelector` - `argsHash` -- `txContent` +- `txContent` -The resulting transaction hash is always emitted during local execution as the first nullifier of the transaction, in order to prevent replay attacks. This is enforced by the private kernel circuit. \ No newline at end of file +The resulting transaction hash is always emitted during local execution as the first nullifier of the transaction, in order to prevent replay attacks. This is enforced by the private kernel circuit. diff --git a/yellow-paper/docs/transactions/validity.md b/yellow-paper/docs/transactions/validity.md index 9d464e0d858..d109bded169 100644 --- a/yellow-paper/docs/transactions/validity.md +++ b/yellow-paper/docs/transactions/validity.md @@ -1,13 +1,19 @@ # Validity conditions -The _validity conditions_ of a transaction define when a [_transaction object_](./tx-object.md) is valid. Nodes should check the validity of a transaction when they receive it either directly or through the p2p pool, and if they found it invalid, should drop it immediately and not broadcast it. +The _validity conditions_ of a transaction define when a [_transaction object_](./tx-object.md) is valid. Nodes should check the validity of a transaction when they receive it either directly or through the p2p pool, and if they find it to be invalid, should drop it immediately and not broadcast it. In addition to being well-formed, the transaction object needs to pass the following checks: + + - **Proof is valid**: The `proof` for the given public `data` should be valid according to a protocol-wide verification key for the final private kernel circuit. -- **No double-spends**: No `nullifier` in the transaction `data` should be already present in the nullifier tree. +- **No duplicate nullifiers**: No `nullifier` in the transaction `data` should be already present in the nullifier tree. - **No pending private function calls**: The `data` private call stack should be empty. -- **Valid historic data**: The tree roots in the block header of `data` must match the tree roots of a block in the chain. +- **Valid historic data**: The tree roots in the block header of `data` must match the tree roots of a historical block in the chain. - **Maximum block number not exceeded**: The transaction must be included in a block with height no greater than the value specified in `maxBlockNum` within the transaction's `data`. - **Preimages must match commitments in `data`**: The expanded fields in the transaction object should match the commitments (hashes) to them in the public `data`. - The `encryptedLogs` should match the `encryptedLogsHash` and `encryptedLogPreimagesLength` in the transaction `data`. @@ -15,4 +21,4 @@ In addition to being well-formed, the transaction object needs to pass the follo - Each public call stack item in the transaction `data` should have a corresponding preimage in the `enqueuedPublicFunctionCalls`. - Each new contract data in transaction `data` should have a corresponding preimage in the `newContracts`. -Note that all checks but the last one are enforced by the base rollup circuit when the transaction is included in a block. \ No newline at end of file +Note that all checks but the last one are enforced by the base rollup circuit when the transaction is included in a block. diff --git a/yellow-paper/docusaurus.config.js b/yellow-paper/docusaurus.config.js index 522eac56374..42b316a995a 100644 --- a/yellow-paper/docusaurus.config.js +++ b/yellow-paper/docusaurus.config.js @@ -39,6 +39,7 @@ const config = { markdown: { mermaid: true, }, + themes: ["@docusaurus/theme-mermaid"], presets: [ @@ -106,6 +107,7 @@ const config = { }, ], }, + footer: { style: "dark", links: [ @@ -139,6 +141,7 @@ const config = { ], copyright: `Copyright © ${new Date().getFullYear()} Aztec Labs, Inc. Built with Docusaurus.`, }, + prism: { theme: lightCodeTheme, darkTheme: darkCodeTheme, diff --git a/yellow-paper/sidebars.js b/yellow-paper/sidebars.js index 5a114dbcf11..bfdc9cc4d8a 100644 --- a/yellow-paper/sidebars.js +++ b/yellow-paper/sidebars.js @@ -20,12 +20,44 @@ const sidebars = { yellowPaperSidebar: [ "intro", + { + label: "Cryptography", + type: "category", + link: { type: "doc", id: "cryptography/index" }, + items: [ + { + label: "Proving System", + type: "category", + link: { + type: "doc", + id: "cryptography/proving-system/performance-targets", + }, + items: [ + "cryptography/proving-system/performance-targets", + "cryptography/proving-system/overview", + "cryptography/proving-system/data-bus", + ], + }, + { + label: "Hashing", + type: "category", + link: { type: "doc", id: "cryptography/hashing/hashing" }, + items: [ + "cryptography/hashing/hashing", + "cryptography/hashing/pedersen", + ], + }, + "cryptography/merkle-trees", + ], + }, { label: "Addresses & Keys", type: "category", link: { type: "doc", id: "addresses-and-keys/index" }, items: [ - "addresses-and-keys/specification", + "addresses-and-keys/address", + "addresses-and-keys/keys-requirements", + "addresses-and-keys/keys", "addresses-and-keys/precompiles", "addresses-and-keys/diversified-and-stealth", ], @@ -80,10 +112,17 @@ const sidebars = { ], }, { - label: "Cross-chain communication", + label: "L1 smart contracts", type: "category", - link: { type: "doc", id: "cross-chain-communication/index" }, - items: ["cross-chain-communication/da"], + link: { type: "doc", id: "l1-smart-contracts/index" }, + items: [ + "l1-smart-contracts/proposal", + ], + }, + { + label: "Data publication and availability", + type: "doc", + id: "data-publication-and-availability/index", }, { label: "Logs", @@ -106,7 +145,7 @@ const sidebars = { { label: "Gas & Fees", type: "category", - link: { type: "doc", id: "gas-and-fees/gas-and-fees" }, + link: { type: "doc", id: "gas-and-fees/index" }, items: [], }, { @@ -119,15 +158,6 @@ const sidebars = { "decentralization/p2p-network", ], }, - { - label: "Cryptography", - type: "category", - link: { type: "doc", id: "cryptography/performance-targets" }, - items: [ - "cryptography/performance-targets", - "cryptography/protocol-overview", - ], - }, // Protocol Statements? { label: "Circuits", diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index 776890efff9..ae297566cb4 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -8,8 +8,9 @@ const TOPICS_IN_SECTIONS = [ ]; const IN_TAG_DESCRIPTION = "The [tag/size](./state-model#tags-and-tagged-memory) to check inputs against and tag the destination with."; +const IN_TAG_DESCRIPTION_NO_FIELD = IN_TAG_DESCRIPTION + " `field` type is NOT supported for this instruction."; const DST_TAG_DESCRIPTION = "The [tag/size](./state-model#tags-and-tagged-memory) to tag the destination with but not to check inputs against."; -const INDIRECT_FLAG_DESCRIPTION = "Toggles whether each memory-offset argument is an indirect offset. 0th bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`."; +const INDIRECT_FLAG_DESCRIPTION = "Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`."; const INSTRUCTION_SET_RAW = [ { @@ -113,7 +114,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -132,7 +133,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -151,7 +152,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -170,7 +171,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -189,7 +190,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -208,7 +209,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's input"}, @@ -226,7 +227,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -245,7 +246,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Bitwise", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"},